5、抽象工厂 abstract factory 将关联组件组成产品 创建型模式

趁热打铁,紧跟着上一节的工厂方法模式。这一节介绍一下抽象工厂模式,以及分析俩个模式的不同

1、何为抽象模式?

抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

在Abstract Factory模式中将会出现抽象工厂,它会将抽象零件组装为抽象产品。也就是说,我们并不关心零件的具体实现,而是只关心接口(API )。我们仅使用该接口( API )将零件组装成为产品。

在Tempate Method模式和Builder模式中,子类这- -层负责方法的具体实现。在Abstract Factory模式中也是一样的。在子类这一层中有 具体的工厂,它负责将具体的零件组装成为具体的产品。

我们赶紧来看看下面这段抽象工厂的示例程序吧。跟着代码看抽象模式!

2、示例程序

效果:

5、抽象工厂 abstract factory 将关联组件组成产品 创建型模式

类图:

5、抽象工厂 abstract factory 将关联组件组成产品 创建型模式

类的一览表:

5、抽象工厂 abstract factory 将关联组件组成产品 创建型模式

类的位置:

5、抽象工厂 abstract factory 将关联组件组成产品 创建型模式

2.1 定义抽象的零件 Item类

package cn.design.abstractfactory.factrory;

/**
* @author lin
* @version 1.0
* @date 2020-07-17 9:11
* @Description Item类是Link类和Tray类的父类(Item有 “ 项目 ” 的意思)。这样 Link类和Tray类就具有可替换性了。
*/
public abstract class Item {
   /**
    * caption字段表示项目的“标题”。
    */
   protected String caption;    public Item(String caption) {
       this.caption = caption;
  }    /**
    * makeHTML方法是抽象方法,需要子类来实现这个方法。该方法会返回HTML文件的内容(需要子类去实现)。
    *
    * @return HTML
    */
   public abstract String makeHTML();
}

2.2 定义抽象的零件组成 Link类

package cn.design.abstractfactory.factrory;

/**
* @author lin
* @version 1.0
* @date 2020-07-17 9:14
* @Description Link类(代码清单8 - 2)是抽象地表示HTML的超链接的类。
* 由于Link类中没有实现父类( Item类)的抽象方法(ma keHTML),因此它也是抽象类。
*/
public abstract class Link extends Item {
   /**
    * url字段中保存的是超链接所指向的地址。乍一看,在Link类中好像一个抽象方法都没有,
    * 但实际上并非如此。
    */
   protected String url;    public Link(String caption, String url) {
       super(caption);
       this.url = url;
  }
}

2.3 定义抽象的零件组成 Tray类

package cn.design.abstractfactory.factrory;

import java.util.ArrayList;
import java.util.List; /**
* @author lin
* @version 1.0
* @date 2020-07-17 9:18
* @Description Tray类(代码清单8 - 3)表示的是-一个含有多个Link类和Tray类的容器( Tray有托盘的意
* 思。请想象成在托盘上放置着-一个- -个项目 )。
* 虽然Tray类也继承了Item类的抽象方法makeHTML,但它并没有实现该方法。因此,Tray
* 类也是抽象类。
*/
public abstract class Tray extends Item {
   protected List<Item> tray = new ArrayList<>();    public Tray(String caption) {
       super(caption);
  }    /**
    * Tray类使用add方法将Link类和Tray类集合在- -起。为了表示集合的对象是“Link类
    * 和Tray类”,我们设置add方法的参数为Link类和Tray类的父类Item类。
    *
    * @param item
    */
   public void add(Item item) {
       tray.add(item);
  } }

2.4 定义抽象的产品 Page 类

package cn.design.abstractfactory.factrory;

import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List; /**
* @author lin
* @version 1.0
* @date 2020-07-17 10:43
* @Description Page类是抽象地表示HTML页面的类。
* 如果将Link和Tray比喻成抽象的“零件”,那么Page类就是抽象的“产品”。
*/
public abstract class Page {
   /**
    * title 和author分别是表示页面标题和页面作者的字段。作者名字通过参数传递给Page类的构造函数。
    */
   protected String title;
   protected String author;
   protected List<Item> content = new ArrayList<>();    public Page(String title, String author) {
       this.title = title;
       this.author = author;
  }    /**
    * 可以使用add方法向页面中增加Item(即Link或Tray)。增加的Item将会在页面中显示出来。
    *
    * @param item 零件
    */
   public void add(Item item) {
       content.add(item);
  }    /**
    * output方法首先根据页面标题确定文件名,接着调用ma keHTML方法将自身保存的HTML
    * 内容写人到文件中。
    * 其中,我们可以去掉如下语句(1 )中的this,将其写为如下语句(2 )那样。
    * writer .write (this . makeHTML()) ;
    * ...... ( 1 )
    * writer . write (makeHTML()) ;
    * ...... (2 )
    * 为了强调调用的是Page类自己的makeHTML方法,我们显式地加上了this。这里调用的
    */
   public void output() {
       try {
           String fileName = title + ".html";
           FileWriter writer = new FileWriter(fileName);
           writer.write(this.makeHTML());
           writer.close();
           System.out.println(fileName + " 编写完成");
      } catch (IOException e) {
           e.printStackTrace();
      }
  }    /**
    * makeHTML方法是一- 个抽象方法。output 方法是一个简单的Template Method模式的方法。
    *
    * @return html 字符串
    */
   public abstract String makeHTML(); }

2.5 定义抽象的工厂 Factory类

package cn.design.abstractfactory.factrory;

/**
* @author lin
* @version 1.0
* @date 2020-07-17 11:00
* @Description TODO
*/
public abstract class Factory {
   /**
    * getFactory 方法通过调用Class类的forName方法来动态地读取类信息,接着使用,
    * newInstance方法生成该类的实例,并将其作为返回值返回给调用者。
    * Class类属于java.lang包,是用来表示类的类。Class 类包含于Java的标准类库中。
    * forName是java.lang.Class的类方法(静态方法),newInstance则是java. lang.
    * Class的实例方法。
    * 请注意,虽然getFactory方法生成的是具体工厂的实例,但是返回值的类型是抽象工厂类型。
    * @param className
    * @return
    */
   public static Factory getFactory(String className) {
       Factory factory = null;
       try {
           factory = (Factory) Class.forName(className).newInstance();
      } catch (InstantiationException | IllegalAccessException e) {
           e.printStackTrace();
      } catch (ClassNotFoundException e) {
           System.out.println("ClassNotFoundException 没有找到 " + className + " 类.");
      }
       return factory;   }
   public abstract Link createLink(String caption, String url);    public abstract Tray createTray(String caption);    /**
    * createLink、createTray. createPage等方法是用于在抽象工厂中生成零件和产品的方
    * 法。这些方法都是抽象方法,具体的实现被交给了Factory类的子类。不过,这里确定了方法的
    * 名字和签名。
    * @param title
    * @param author
    * @return
    */
   public abstract Page createPage(String title, String author);
}

2.6 定义具体的工厂 ListFactory类

package cn.design.abstractfactory.listfactory;

import cn.design.abstractfactory.factrory.Factory;
import cn.design.abstractfactory.factrory.Link;
import cn.design.abstractfactory.factrory.Page;
import cn.design.abstractfactory.factrory.Tray; /**
* @author lin
* @version 1.0
* @date 2020-07-17 11:29
* @Description TODO
*/
public class ListFactory extends Factory {    @Override
   public Link createLink(String caption, String url) {
       return new ListLink(caption, url);
  }    @Override
   public Tray createTray(String caption) {
       return new ListTray(caption);
  }    @Override
   public Page createPage(String title, String author) {
       return new ListPage(title, author);
  }
}

2.7 定义具体的零件 ListLink类

package cn.design.abstractfactory.listfactory;

import cn.design.abstractfactory.factrory.Link;

/**
* @author lin
* @version 1.0
* @date 2020-07-17 11:31
* @Description TODO
*/
public class ListLink extends Link {    public ListLink(String caption, String url) {
       super(caption, url);
  }    @Override
   public String makeHTML() {
       return "<li><a href =\"" + url + "\">" + caption + "</a></li>\n";
  }
}

2.8 定义具体的零件 ListTray类

package cn.design.abstractfactory.listfactory;

import cn.design.abstractfactory.factrory.Item;
import cn.design.abstractfactory.factrory.Tray; import java.util.Iterator; /**
* @author lin
* @version 1.0
* @date 2020-07-17 11:32
* @Description TODO
*/
public class ListTray extends Tray {
   public ListTray(String caption) {
       super(caption);
  }    @Override
   public String makeHTML() {
       StringBuffer buffer = new StringBuffer();
       buffer.append("<li>\n");
       buffer.append(caption + "\n");
       buffer.append("<ul>\n");
       Iterator it = tray.iterator();
       while (it.hasNext()) {
           Item item = (Item) it.next();
           buffer.append(item.makeHTML());
      }
       buffer.append("</ul>\n");
       buffer.append("</li>\n");
       return buffer.toString();   }
}

2.9 定义具体的产品 ListPage类

package cn.design.abstractfactory.listfactory;

import cn.design.abstractfactory.factrory.Item;
import cn.design.abstractfactory.factrory.Page; import java.util.Iterator; /**
* @author lin
* @version 1.0
* @date 2020-07-17 11:34
* @Description TODO
*/
public class ListPage extends Page {
   public ListPage(String title, String author) {
       super(title, author);
  }    @Override
   public String makeHTML() {
       StringBuffer buffer = new StringBuffer();
       buffer.append("<html><head><title>" + title + "</title></head>\n");
       buffer.append("<body>\n");
       buffer.append("<h1>" + title + "</h1>\n");
       buffer.append("<ul>\n");
       Iterator it = content.iterator();
       while (it.hasNext()) {
           Item item = (Item) it.next();
           buffer.append(item.makeHTML());
      }
       buffer.append("</ul>\n");
       buffer.append("<hr><address>" + author + "</address>");
       buffer.append("</body></html>\n");
       return buffer.toString();   }
}

2.10 测试Main类

package cn.design.abstractfactory;

import cn.design.abstractfactory.factrory.Factory;
import cn.design.abstractfactory.factrory.Link;
import cn.design.abstractfactory.factrory.Page;
import cn.design.abstractfactory.factrory.Tray;
import cn.design.abstractfactory.listfactory.ListFactory;
import cn.design.abstractfactory.tablefactory.TableFactory;
import com.alibaba.fastjson.JSON; /**
* @author lin
* @version 1.0
* @date 2020-07-17 9:10
* @Description TODO
*/
public class Main {
   public static void main(String[] args) {
       Factory factory = Factory.getFactory(ListFactory.class.getName());
//       Factory factory = Factory.getFactory(TableFactory.class.getName());        Link people = factory.createLink("人民日报", "http://www.people.com.cn/");
       Link gmw = factory.createLink(" 光明日报", "http://www.gmw.cn/");
       Link usYahoo = factory.createLink("Yahoo!", "http://www.yahoo.com/");
       Link jpYahoo = factory.createLink("Yahoo!Japan", "http://ww.yahoo.co.jp/");
       Link excite = factory.createLink("Excite", "http://www.excite.com/");
       Link google = factory.createLink("Google", "http://www.google.com/");        Tray trayNews = factory.createTray(" 日报");
       trayNews.add(people);
       trayNews.add(gmw);        Tray trayYaHoo = factory.createTray("Yahoo!");
       trayYaHoo.add(usYahoo);
       trayYaHoo.add(jpYahoo);        Tray traySearch = factory.createTray("检索引擎");
       traySearch.add(trayYaHoo);
       traySearch.add(excite);
       traySearch.add(google);        Page page = factory.createPage("LinkPage", " 发哥讲");
       page.add(trayNews);
       page.add(traySearch);
       page.output();
  }
}

运行效果如开篇效果图

3、改造成table工厂示例

3.1 定义TableFactory类

package cn.design.abstractfactory.tablefactory;

import cn.design.abstractfactory.factrory.Factory;
import cn.design.abstractfactory.factrory.Link;
import cn.design.abstractfactory.factrory.Page;
import cn.design.abstractfactory.factrory.Tray; /**
* @author lin
* @version 1.0
* @date 2020-07-17 14:53
* @Description TODO
*/
public class TableFactory extends Factory {
   @Override
   public Link createLink(String caption, String url) {
       return new TableLink(caption, url);
  }    @Override
   public Tray createTray(String caption) {
       return new TableTray(caption);
  }    @Override
   public Page createPage(String title, String author) {
       return new TablePage(title, author);
  }
}

3.2定义TableLink类

package cn.design.abstractfactory.tablefactory;

import cn.design.abstractfactory.factrory.Link;

/**
* @author lin
* @version 1.0
* @date 2020-07-17 14:54
* @Description TODO
*/
public class TableLink extends Link {
   public TableLink(String caption, String url) {
       super(caption, url);
  }    @Override
   public String makeHTML() {
       return "<td><a href=\"" + url + "\">" + caption + "</a></td>\n";   }
}

3.3定义TableTray类

package cn.design.abstractfactory.tablefactory;

import cn.design.abstractfactory.factrory.Item;
import cn.design.abstractfactory.factrory.Tray; import java.util.Iterator; /**
* @author lin
* @version 1.0
* @date 2020-07-17 14:56
* @Description TODO
*/
public class TableTray extends Tray {
   public TableTray(String caption) {
       super(caption);
  }    @Override
   public String makeHTML() {
       StringBuffer buffer = new StringBuffer();
       buffer.append("<td>");
       buffer.append("<table width=\"100%\" border=\"1\"><tr>");
       buffer.append("<td bgcolor=\"#ccccc\" align=\"center\" colspan=\"" + tray.size() + "\"><b>" + caption + "</b></td>");
       buffer.append("</tr>\n");
       buffer.append("<tr>\n");
       Iterator it = tray.iterator();
       while (it.hasNext()) {
           Item item = (Item) it.next();
           buffer.append(item.makeHTML());
      }
       buffer.append("</tr></table>");
       buffer.append("</td>");
       return buffer.toString();   }
}

3.4定义TablePage类

package cn.design.abstractfactory.tablefactory;

import cn.design.abstractfactory.factrory.Item;
import cn.design.abstractfactory.factrory.Page; import java.util.Iterator; /**
* @author lin
* @version 1.0
* @date 2020-07-17 14:57
* @Description TODO
*/
public class TablePage extends Page {
   public TablePage(String title, String author) {
       super(title, author);
  }    @Override
   public String makeHTML() {
       StringBuffer buffer = new StringBuffer();
       buffer.append("<html><head><title>" + title + "</title></head>\n");
       buffer.append("<body>\n");
       buffer.append("<h1>" + title + "</h1>\n");
       buffer.append("<table width=\"80号\" border=\"3\">\n");
       Iterator it = content.iterator();
       while (it.hasNext()) {
           Item item = (Item) it.next();
           buffer.append("<tr>" + item.makeHTML() + "</tr>");
      }
       buffer.append("</table>\n");
       buffer.append("<hr><address>" + author + "</address>");
       buffer.append("</body></html>\n");
       return buffer.toString();   }
}

3.5 测试类

测试类与2.10一样。

使用这个即可

Factory factory = Factory.getFactory(TableFactory.class.getName());

3.6效果

5、抽象工厂 abstract factory 将关联组件组成产品 创建型模式

4、分析各个模块的作用

4.1 抽象工厂类图

5、抽象工厂 abstract factory 将关联组件组成产品 创建型模式

4.2作用介绍

4.2.1 AbstractProduct (抽象产品)

AbstractProduct角色负责定义AbstractFactory角色所生成的抽象零件和产品的接口( API)。在示例程序中,由Link类、Tray类和Page类扮演此角色。

4.2.2 AbstractFactory (抽象工厂)

AbstractFactory角色负责定义用于生成抽象产品的接口(API)。在示例程序中,由Factory类扮演此角色。

4.2.3 Client (委托者)

Client角色仅会调用AbstractFactory角色和AbstractProduct角色的接口( API)来进行工作,对于具体的零件、产品和工厂- -无所知。在示例程序中,由Main类扮演此角色。图8-9省略了Client这- -角色。

4.2.4 ConcreteProduct (具体产品)

ConcreteProduct角色负责实现AbstractProduct角色的接口( API)。在示例程序中,由以下包中的以下类扮演此角色。

●listfactory包: ListLink类、ListTray类和ListPage类●tablefactory包: TableLink类、TableTray 类和TablePage类

4.2.5 ConcreteFactory (具体工厂)

ConcreteFactory角色负责实现AbstractFactory角色的接口( API)。在示例程序中,由以下包中的以下类扮演此角色。

●listfactory包: Listfactory类●tablefactory 包: Tablefactory类

5、总结

无论是简单工厂模式,工厂方法模式,还是抽象工厂模式,他们都属于工厂模式,在形式和特点上也是极为相似的,他们的最终目的都是为了解耦。在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为他们之间的演变常常是令人琢磨不透的。经常你会发现,明明使用的工厂方法模式,当新需求来临,稍加修改,加入了一个新方法后,由于类中的产品构成了不同等级结构中的产品族,它就变成抽象工厂模式了;而对于抽象工厂模式,当减少一个方法使的提供的产品不再构成产品族之后,它就演变成了工厂方法模式。所以,在使用工厂模式时,只需要关心降低耦合度的目的是否达到了。

5.1 抽象工厂模式的优点

抽象工厂模式除了具有工厂方法模式的优点外,最主要的优点就是可以在类的内部对产品族进行约束。所谓的产品族,一般或多或少的都存在一定的关联,抽象工厂模式就可以在类内部对产品族的关联关系进行定义和描述,而不必专门引入一个新的类来进行管理。

5.2 抽象工厂模式的缺点

产品族的扩展将是一件十分费力的事情,假如产品族中需要增加一个新的产品,则几乎所有的工厂类都需要进行修改。所以使用抽象工厂模式时,对产品等级结构的划分是非常重要的。

5.3 适用场景

当需要创建的对象是一系列相互关联或相互依赖的产品族时,便可以使用抽象工厂模式。说的更明白一点,就是一个继承体系中,如果存在着多个等级结构(即存在着多个抽象类),并且分属各个等级结构中的实现类之间存

在着一定的关联或者约束,就可以使用抽象工厂模式。假如各个等级结构中的实现类之间不存在关联或约束,则

使用多个独立的工厂来对产品进行创建,则更合适一点。

5.4 对比

抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。他与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。

在抽象工厂模式中,有一个产品族的概念:所谓的产品族,是指位于不同产品等级结构中功能相关联的产品组成的家族。抽象工厂模式所提供的一系列产品就组成一个产品族;而工厂方法提供的一系列产品称为一个等级结构。我们依然拿生产汽车的例子来说明他们之间的区别。

自己尝试写着代码区体会。那种方式方便就是用那种,也是根据场景的改变而做出选择!!

6、延伸( 生成实例的方法)

此处作为彩蛋~~~~ 扩展小知识

6.1 new

new 的方式 常用 , 不用多说。

创建一个日期类, 实例:

new Date();

6.2 clone

package cn.design.abstractfactory.clone;

import java.io.Serializable;

/**
* @author lin
* @version 1.0
* @date 2020-07-17 17:02
* @Description TODO
*/
public class User implements Serializable, Cloneable {
   private static final long serialVersionUID = 6695447736493L;
   String name;
   int age;
   Object obj;    public User(String name, int age, Object obj) {
       this.name = name;
       this.age = age;
       this.obj = obj;
  }    public User() {
  }    public User createClone() {
       User user = null;
       try {
           user = (User) super.clone();
      } catch (CloneNotSupportedException e) {
           e.printStackTrace();
      }
       return user;
  }    @Override
   public String toString() {
       return "User{" +
               "name='" + name + '\'' +
               ", age=" + age +
               ", obj=" + obj +
               '}';
  }    public static void main(String[] args) throws CloneNotSupportedException {
       User user = new User("发哥讲", 23, "人逢知己千杯少,难得在漫漫人生路上能认识你");
       System.out.println(user.toString());
       User clone = user.createClone();
       System.out.println("clone: " +clone.toString());
  }
}

clone 包含 浅拷贝和深拷贝, 后续有时间 会出一个专辑,专门介绍

6.3 反射

      Class<?> aClass = Class.forName(User.class.getName());
      Object o = aClass.newInstance();
      System.out.println(o);

反射也是后续会出一个专辑, 通过反射 可以获取到类的所有信息,还有类名,属性,方法上的注解.

自定义注解也是一个高级进阶专题的,放心各位,都不会少!!!

发哥讲

5、抽象工厂 abstract factory 将关联组件组成产品 创建型模式

如果你觉得文章还不错,就请点击右上角选择发送给朋友或者转发到朋友圈~

● 扫码关注公众号

上一篇:mysql存储过程和触发器的应用


下一篇:HTC与英特尔联手打造无线VR解决方案