字面意思:抽象工厂,抽象工厂的工作是将抽象零件组装成抽象产品。

抽象零件:Item类:

抽象零件类,定义抽象方法。

  1. public abstract class Item {
  2. protected String caption;
  3. public Item(String caption) {
  4. this.caption = caption;
  5. }
  6. public abstract String makeHTML();
  7. }

抽象的零件:Link类:

继承了Item类,将自己和Item相关联,自己只储存url链接,caption放在Item中。

  1. public abstract class Link extends Item {
  2. protected String url;
  3. public Link(String caption,String url) {
  4. super(caption);
  5. this.url = url;
  6. }
  7. }

抽象的零件:Tray类:

代表一个托盘,包含多个Link类和Tray类的容器。

  1. public abstract class Tray extends Item{
  2. protected ArrayList tray=new ArrayList();
  3. public Tray(String caption) {
  4. super(caption);
  5. }
  6. public void add(Item item){
  7. tray.add(item);
  8. }
  9. }

抽象的产品:Page类:

将Link和Tray比喻成抽象的“零件”,那么Page类就是抽象的产品。可以使用add方法向页面中增加Item(Link或Tray)。

  1. public abstract class Page {
  2. protected String title;
  3. protected String author;
  4. protected ArrayList content = new ArrayList();
  5. public Page(String title, String author) {
  6. this.title = title;
  7. this.author = author;
  8. }
  9. public void add(Item item){
  10. content.add(item);
  11. }
  12. public void output(){
  13. try {
  14. String fileName = title + ".html";
  15. FileWriter writer = new FileWriter(fileName);
  16. writer.write(this.makeHTML());
  17. writer.close();
  18. System.out.println(fileName+"编写完成");
  19. } catch (IOException e) {
  20. e.printStackTrace();
  21. }
  22. }
  23. public abstract String makeHTML();
  24. }

抽象的工厂:Factory类:

getFactory方法可以根据指定的类名生成具体工厂的实例。将参数className指定为具体工厂的类名所对应的字符串。可以通过调用Class类的forName方法来动态的读取类信息,接着使用newInstance方法生成该类的实例,并将其作为返回值返回给调用者。

  1. public abstract class Factory {
  2. public static Factory getFactory(String className){
  3. Factory factory = null;
  4. try {
  5. factory = (Factory)Class.forName(className).newInstance();
  6. } catch (InstantiationException e) {
  7. e.printStackTrace();
  8. } catch (IllegalAccessException e) {
  9. e.printStackTrace();
  10. } catch (ClassNotFoundException e) {
  11. e.printStackTrace();
  12. }
  13. return factory;
  14. }
  15. public abstract Link createLinks(String caption,String url);
  16. public abstract Tray createTray(String caption);
  17. public abstract Page createPage(String title,String author);
  18. }

使用工厂将零件组装成为产品:Main类

在Main类中使用抽象工厂生产零件并将零件组装成产品。

  1. public class Main {
  2. public static void main(String[] args) {
  3. if (args.length != 1) {
  4. System.out.println("Usage:java Main class.name.of.ConcreteFactory");
  5. System.out.println("Example 1: java Main listFactory.ListFactory");
  6. System.exit(0);
  7. }
  8. Factory factory = Factory.getFactory(args[0]);
  9. Link people = factory.createLinks("人民日报","http://www.people.com.cn/");
  10. Link gmw = factory.createLinks("光明日报", "http://www.people.com.cn/");
  11. Link us_yahoo = factory.createLinks("Yahoo!", "http://www.yahoo.com/");
  12. Link jp_yahoo = factory.createLinks("Yahoo!Japan", "http://www.yahoo.co.jp/");
  13. Link excite = factory.createLinks("Excite", "http://www.excite.com/");
  14. Link google = factory.createLinks("Google", "http://www.google.com/");
  15. Tray trayNews = factory.createTray("日报");
  16. trayNews.add(people);
  17. trayNews.add(gmw);
  18. Tray trayYahoo = factory.createTray("Yahoo!");
  19. trayYahoo.add(us_yahoo);
  20. trayYahoo.add(jp_yahoo);
  21. Tray traySearch = factory.createTray("检索引擎");
  22. traySearch.add(trayYahoo);
  23. traySearch.add(excite);
  24. traySearch.add(google);
  25. Page page = factory.createPage("LinkPage", "杨文轩");
  26. page.add(trayNews);
  27. page.add(traySearch);
  28. page.output();
  29. }
  30. }

具体的工厂:ListFactory类

工厂的实现类。

  1. public class ListFactory extends Factory{
  2. @Override
  3. public Link createLinks(String caption, String url) {
  4. return new ListLink( caption, url);
  5. }
  6. @Override
  7. public Tray createTray(String caption) {
  8. return new ListTray(caption);
  9. }
  10. @Override
  11. public Page createPage(String title, String author) {
  12. return new ListPage(title,author);
  13. }
  14. }

具体的零件:ListLink类

  1. public class ListLink extends Link{
  2. public ListLink(String caption, String url) {
  3. super(caption, url);
  4. }
  5. @Override
  6. public String makeHTML() {
  7. return "listLink"+url+caption;
  8. }
  9. }

具体的零件:ListTray类

  1. public class ListTray extends Tray{
  2. public ListTray( String author) {
  3. super(author);
  4. }
  5. @Override
  6. public String makeHTML() {
  7. return "ListTray"+caption;
  8. }
  9. }

具体的零件:ListPage类

  1. public class ListPage extends Page{
  2. public ListPage(String title, String author) {
  3. super(title, author);
  4. }
  5. @Override
  6. public String makeHTML() {
  7. return "ListPage"+title+author;
  8. }
  9. }

Abstract Factory模式中的登场角色:

AbstractProduct(抽象产品):

主要负责定义AbstractFactory角色中所生成的抽象零件和产品的接口。上述中的Link类、Tray类、Page类扮演这个角色。

AbstractFactory(抽象工厂):

主要负责定义用于生成抽象产品的接口;在示例程序中,由Factory扮演这个角色。调用抽象产品

Client(委托者):

仅仅会调用抽象工厂和抽象产品的接口来进行工作,对具体的零件、产品和工厂一无所知。

ConcreteProduct(具体产品):

负责实现抽象产品的具体接口。

ConcreteFactory(具体工厂):

负责实现抽象工厂的接口。实现抽象工厂中的抽象方法,调用具体的产品。

思路:

易于增加具体的工厂:

在Abstract Factory模式中增加具体的工厂是非常容易的,假设需要在示例程序中增加新的具体工厂,那么需要做的仅仅是编写抽象产品的子类,并实现抽象工厂中定义的抽象方法。也就是只需要将抽象部分具体化即可,不需要修改已有的代码部分,非常优雅。

难以增加新的零件:

如果需要在Abstract Factory模式中增加新的零件时会怎么样?需要对所有的具体工厂进行相应的修改才行。已经编写完成的具体工厂越多,需要做的修改就越多。

相关的设计模式:

Builder模式:

Builder模式是分阶段地制作复杂实例,而Abstract Factory则是通过调用抽象产品的接口来组装抽象产品,生成具有复杂结构的实例。

Factory Method模式:

有时Abstract Factory模式中零件和产品的生成会使用到Factory Method模式。

Composite模式:

有时Abstract Factory模式在制作产品时会使用Composite模式。

Singleton模式:

有时Abstract Factory模式在制作产品时会使用Singleton模式。

问题:

将子类设置为protected,子类可以访问该字段,但是如果修改为private,会存在哪些优缺点呢?

设置为private的优点:

  1. - 方法更加安全;
  2. - 子类不会依赖于父类字段的实现。

缺点:

  1. - 必须编写一些方法让外部可以访问自身的字段属性。