博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
浅析设计模式(三)——抽象工厂模式
阅读量:6524 次
发布时间:2019-06-24

本文共 8371 字,大约阅读时间需要 27 分钟。

抽象工厂模式(Abstract-Factory,创建型模式)

本文的结构:

一、抽象工厂模式的定义

  提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

  前面【】中介绍的简单工厂方法,虽然已经对变化的部分进行了封装,但是这里只由一个对象负责所有的具体类的实例化,因此每次有新增对象类型时,都需要改变工厂的源码进行扩展。而【】中介绍的工厂方法模式,则对简单工厂方法进行了最直接的封装和抽象,把创建对象的具体操作进行了分离,便于扩展和维护。这两种做法都是用于创建单类对象。

  从某种角度来看,抽象工厂模式也是类似的,都是把创建对象的动作进行了封装。但是抽象工厂模式意在创建相关或依赖对象的家族。从抽象工厂模式的实现来看,它通过组合委托给具体的工厂来实现,对象的创建被实现在工厂接口所暴露出来的方法中,通常用于创建产品家族或者相关集合。而这些工厂通常使用工厂方法来实现具体的产品创建。做个最简化,如果抽象工厂也只是创建一类产品,而不考虑后续的扩展之类的,是可以直接用工厂方法来实现的。

  这里有必要对“相关或依赖对象的家族”做一个简单地说明,举个栗子,假如要创建的对象是台电脑,那么像键盘、鼠标、显示器、主机等等,就可以看成是“相关或依赖对象的家族”。下面要举的栗子也是类似的,也还是拿Pizza的例子,Pizza有各种原料,这里从简,只举出Cheese奶酪、Veggies蔬菜、Clams蛤等原料进行说明,这里的创建对象,实际上是创建了包含各类原料的Pizza,也即就是提到的“相关或依赖对象的家族”。

二、抽象工厂模式的参与者及其角色

1. AbstractFactory

  • 声明一个创建抽象产品对象的操作接口

2. ConcreteFactory

  • 实现创建具体产品对象的操作

3. AbstractProduct

  • 为一类产品对象声明一个接口

4. ConcreteProduct

  • 定义一个将被相应的具体工厂创建的产品对象
  • 实现AbstractProduct接口

5. Client

  • 仅使用由AbstractFactory和AbstractProduct类声明的接口。

三、抽象工厂模式的类图 

四、抽象工厂模式的示例

1. AbstractFactory:声明一个创建抽象产品对象的操作接口,用于创建相关或依赖对象的家族。

1 /** 2  *  3  * 

4 * Reference : Head-First-Design-Patterns 5 * 6 */ 7 public interface PizzaIngredientFactory { 8 public Cheese createCheese(); 9 public Veggies[] createVeggies();10 public Clams createClam();11 }

2. ConcreteFactory:实现创建具体产品对象的操作,这里就是最简单的直接创建对象,

例1:

1 /** 2  *  3  * 

4 * Reference : Head-First-Design-Patterns 5 * 6 */ 7 public class NYPizzaIngredientFactory implements PizzaIngredientFactory{ 8 9 @Override10 public Veggies[] createVeggies() {11 Veggies veggies[] = { new Garlic(), new Onion(), new Mushroom()};12 return veggies;13 }14 15 @Override16 public Clams createClam() {17 return new FreshClams();18 }19 20 @Override21 public Cheese createCheese() {22 return new ReggianoCheese();23 }24 }

 例2

1 /** 2  *  3  * 

4 * Reference : Head-First-Design-Patterns 5 * 6 */ 7 public class ChicagoPizzaIngredientFactory implements PizzaIngredientFactory{ 8 9 @Override10 public Cheese createCheese() {11 return new MozzarellaCheese();12 }13 @Override14 public Veggies[] createVeggies() {15 Veggies veggies[] = { new Onion(), new Garlic()};16 return veggies;17 }18 @Override19 public Clams createClam() {20 return new FrozenClams();21 }22 }

 从这里可以看出,上面的具体工厂其实就是工厂方法的简化,不带任何判断就直接创建了具体的对象。当然也是可以像前面提到的工厂方法模式一样,带参数,然后根据参数进行具体对象的创建。

3. AbstractProduct:为一类产品对象声明一个接口,以上创建的“相关或依赖对象的家族”其实就是这里需要用到的。

1 /** 2  *  3  * 

4 * Reference : Head-First-Design-Patterns 5 * 6 */ 7 public abstract class Pizza { 8 String name; 9 10 Veggies veggies[];11 Cheese cheese;12 Clams clam;13 14 abstract void prepare();15 16 void bake() {17 System.out.println("Bake for 25 minutes at 350");18 }19 20 void cut() {21 System.out.println("Cutting the pizza into diagonal slices");22 }23 24 void box() {25 System.out.println("Place pizza in official PizzaStore box");26 }27 28 void setName(String name) {29 this.name = name;30 }31 32 String getName() {33 return name;34 }35 36 public String toString() {37 StringBuffer result = new StringBuffer();38 result.append("---- " + name + " ----\n");39 40 if (cheese != null) {41 result.append(cheese);42 result.append("\n");43 }44 if (veggies != null) {45 for (int i = 0; i < veggies.length; i++) {46 result.append(veggies[i]);47 if (i < veggies.length-1) {48 result.append(", ");49 }50 }51 result.append("\n");52 }53 if (clam != null) {54 result.append(clam);55 result.append("\n");56 }57 return result.toString();58 }59 }

 4. ConcreteProduct:实现AbstractProduct接口,定义一个将被相应的具体工厂创建的产品对象。

这里简单地举个栗子即可,可以看到,这里组合使用了创建对象的工厂,然后根据需要由工厂创建具体的对象。

1 /** 2  *  3  * 

4 * Reference : Head-First-Design-Patterns 5 * 6 */ 7 public class VeggiePizza extends Pizza{ 8 PizzaIngredientFactory ingredientFactory; 9 10 public VeggiePizza(PizzaIngredientFactory ingredientFactory) {11 this.ingredientFactory = ingredientFactory;12 }13 14 @Override15 void prepare() {16 System.out.println("Preparing " + name);17 cheese = ingredientFactory.createCheese();18 veggies = ingredientFactory.createVeggies();19 }20 }

 类似的

1 /** 2  *  3  * 

4 * Reference : Head-First-Design-Patterns 5 * 6 */ 7 public class ClamPizza extends Pizza{ 8 PizzaIngredientFactory ingredientFactory; 9 10 public ClamPizza(PizzaIngredientFactory ingredientFactory) {11 this.ingredientFactory = ingredientFactory;12 }13 14 void prepare() {15 System.out.println("Preparing " + name);16 cheese = ingredientFactory.createCheese();17 clam = ingredientFactory.createClam();18 }19 }

 5. Client:仅使用由AbstractFactory和AbstractProduct类声明的接口。

  这里的例子曲折了点,不过也可以大概说明要表达的意思。获取到具体Pizza的流程如下:

  1. 首先创建一个纽约披萨店,即PizzaStore nyStore = new NYPizzaStore();
  2. 通过披萨店下订单,即Pizza pizza = nyStore.orderPizza("cheese");
  3. orderPizza("cheese")首先调用Pizza pizza = createPizza("cheese");
  4. createPizza("cheese")中就涉及到了具体的工厂类,pizza = new CheesePizza(ingredientFactory);
  5. 接下来就是具体的准备Pizza了,调用pizza.prepare()时,便是由工厂具体地创建所有对象家族了。如下
1 void prepare() {2     System.out.println("Preparing " + name);3     cheese = ingredientFactory.createCheese();4     //...其他的原料产品,如Veggies、Clams等,可能只需要一个,也可能全部都要。这里略去5 }

 顺着这个思路走:

PizzaStore nyStore = new NYPizzaStore()  →

    Pizza pizza = nyStore.orderPizza("cheese")  →

        Pizza pizza = createPizza("cheese")  →

            pizza = new CheesePizza(ingredientFactory)  →

                pizza.prepare()  →

                    ingredientFactory创建具体的产品。。。

测试用的主类和主函数:

1 /** 2  * This is the test-main. 3  * 

4 * Reference : Head-First-Design-Patterns 5 * 6 */ 7 public class PizzaTestApp { 8 public static void main(String[] args) { 9 PizzaStore nyStore = new NYPizzaStore();10 PizzaStore chicagoStore = new ChicagoPizzaStore();11 12 Pizza pizza = nyStore.orderPizza("cheese");13 System.out.println("Ethan ordered a " + pizza + "\n");14 15 pizza = chicagoStore.orderPizza("cheese");16 System.out.println("Joel ordered a " + pizza + "\n");17 18 pizza = nyStore.orderPizza("clam");19 System.out.println("Ethan ordered a " + pizza + "\n");20 21 pizza = chicagoStore.orderPizza("clam");22 System.out.println("Joel ordered a " + pizza + "\n");23 24 25 pizza = nyStore.orderPizza("veggie");26 System.out.println("Ethan ordered a " + pizza + "\n");27 28 pizza = chicagoStore.orderPizza("veggie");29 System.out.println("Joel ordered a " + pizza + "\n");30 }31 }

 抽象类PizzaStore

1 /** 2  *  3  * 

4 * Reference : Head-First-Design-Patterns 5 * 6 */ 7 public abstract class PizzaStore { 8 protected abstract Pizza createPizza(String item); 9 10 public Pizza orderPizza(String type) {11 Pizza pizza = createPizza(type);12 System.out.println("--- Making a " + pizza.getName() + " ---");13 pizza.prepare();14 pizza.bake();15 pizza.cut();16 pizza.box();17 return pizza;18 }19 }

 继承抽象类PizzaStore的具体实现类NYPizzaStore。

1 /** 2  *  3  * 

4 * Reference : Head-First-Design-Patterns 5 * 6 */ 7 public class NYPizzaStore extends PizzaStore{ 8 protected Pizza createPizza(String item) { 9 Pizza pizza = null;10 PizzaIngredientFactory ingredientFactory = 11 new NYPizzaIngredientFactory();12 13 if (item.equals("cheese")) {14 15 pizza = new CheesePizza(ingredientFactory);16 pizza.setName("New York Style Cheese Pizza");17 18 } else if (item.equals("veggie")) {19 20 pizza = new VeggiePizza(ingredientFactory);21 pizza.setName("New York Style Veggie Pizza");22 23 } else if (item.equals("clam")) {24 25 pizza = new ClamPizza(ingredientFactory);26 pizza.setName("New York Style Clam Pizza");27 28 }29 return pizza;30 }31 }

简单地总结,就是使用组合工厂类创建了包含一系列相关对象的具体产品对象。

 五、参考

1、参考《Head First设计模式》和GoF《设计模式:可复用面向对象软件的基础》

2、代码可参考【】、UML类图参考【】

转载于:https://www.cnblogs.com/wpbxin/p/9237036.html

你可能感兴趣的文章
redis简介
查看>>
Mac下android环境搭建
查看>>
Visual Studio及TFS进行单元测试、负载测试、代码覆盖率、每日构建配置
查看>>
创建Visual Studio项目模版向导的几篇参考文章
查看>>
深入浅出SQL Server Replication第一篇:走近Replication(上)
查看>>
Windows 8,VS 2012,SQL Server 2012,Office 2013使用体验
查看>>
c++中dll的种类用法分析
查看>>
[TopCoder][SRM] SRM 562 DIV 2
查看>>
PyQt4安装方法 - - ITeye技术网站
查看>>
SQLSERVER是怎麽通过索引和统计信息来找到目标数据的(第一篇)
查看>>
获取线程结束代码(Exit Code)
查看>>
QT 跨平台的C++应用和UI开发库
查看>>
简明 Vim 练级攻略 | 酷壳 - CoolShell.cn
查看>>
LocalAlloc,VirtualAlloc,malloc,new的异同
查看>>
关于 IE firefox Chrome下的通过用js 关闭窗口的一些问题
查看>>
回调函数
查看>>
win7 x64 jdk1.7.0_51
查看>>
45 Useful Oracle Queries--ref
查看>>
这些开源项目,你都知道吗?(持续更新中...)[原创]
查看>>
小菜学习设计模式(四)—原型(Prototype)模式
查看>>