抽象工厂模式(Abstract Factory Pattern)
- 抽象工厂模式概述
定义:提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类
抽象工厂抽象工厂,顾名思义,就是比工厂模式更抽象的工厂模式。在工厂模式中,一个具体工厂只负责生产一个具体产品。而在抽象工厂模式中,一个具体工厂可以生产一组相关的产品,这些产品称为产品族,产品族中的每一个产品部分属于每一个产品继承等级结构
首先我们先了解下什么是产品族和产品等级结构。产品等级结构即产品的继承结构,好比一个抽象类是汽车,其子类包括奔驰,宝马,大众,保时捷.....这样抽象汽车与具体汽车品牌之间构成了一个产品等级结构,抽象汽车类是父类,具体汽车类是子类。产品族,在抽象工厂模式中,产品族是指由同一个工厂生产的,属于不同产品等级结构中的一组产品。如苹果公司生产的电脑,手机,平板,手表......构成一个产品族
那么,有这两个东西又有什么用呢?我们不妨思考下,在生活中,有不少工厂,每个工厂中也生产各种不同的产品。我们又如何定位到某个具体的产品呢?
如上图,共有15个不同的图形(颜色或样式都不一样),每一行对应一个具体工厂所产生的具体产品(构成产品族),我们只需要指明产品所处的产品族和它所属的产品等级结构,就可以定位到对应的产品。如第4行(第4个产品族)的第三个产品等级结构,就可以定位到那个椭圆形
- 与工厂方法模式的区别
工厂方法模式针对的是一个产品等级结构,而抽象工厂模式面对多个产品等级结构,一个工厂等级结构负责多个不同的产品等级结构中的产品对象的创建。而在工厂方法模式中,一个工厂等级结构生产一个产品等级结构。上述图中的产品如果在工厂方法模式中,需要15个具体工厂,而在抽象工厂模式中,只需要5个工厂,大大减少了工厂类的个数
- 抽象工厂模式的实现
结构:
- AbstractFactory(抽象工厂):声明了一组用于创建一族产品的方法,每个方法对应一个产品
- ConcreteFactory(具体工厂):实现在抽象工厂中声明的创建产品的方法,生成具体产品,构成产品族
- AbstractProduct(抽象产品):为每种产品声明接口,它声明了产品具有的业务方法
- ConcreteProduct(具体产品):定义具体产品的具体生产对象,实现抽象接口中声明的业务方法
- 抽象工厂模式应用实例
在每个OS中,都有一个图形构建组成的构件家族,可以通过一个抽象角色给出功能定义,而由具体子类给出不同OS中的具体实现,例如下两个产品结构,分别是Button和Text,同时包含三个产品族,即Unix产品族,Linux产品族,Windows产品族,请实现该结构
结构:
实现:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace AbstractFactory 7 { 8 9 interface ComponentFactory//抽象工厂接口 10 { 11 Button CreateButton(); 12 Text CreateText(); 13 } 14 15 public interface Button//抽象按钮产品接口 16 { 17 void Display(); 18 } 19 public interface Text//抽象文本产品接口 20 { 21 void Display(); 22 } 23 24 public class WindowsButton : Button //具体Windows产品 25 { 26 public void Display() 27 { 28 Console.WriteLine("创建Window Button"); 29 } 30 } 31 32 public class WindowsText : Text 33 { 34 public void Display() 35 { 36 Console.WriteLine("创建Window Text"); 37 } 38 } 39 40 public class LinuxButton : Button//具体Linux产品 41 { 42 public void Display() 43 { 44 Console.WriteLine("创建Linux Button"); 45 } 46 } 47 48 public class LinuxText : Text 49 { 50 public void Display() 51 { 52 Console.WriteLine("创建Linux Text"); 53 } 54 } 55 56 public class UnixButton : Button//具体Unix产品 57 { 58 public void Display() 59 { 60 Console.WriteLine("创建Unix Button"); 61 } 62 } 63 64 public class UnixText : Text 65 { 66 public void Display() 67 { 68 Console.WriteLine("创建Unix Text"); 69 } 70 } 71 72 public class WindowsFactory : ComponentFactory//具体Windows控件工厂 73 { 74 public Button CreateButton() 75 { 76 return new WindowsButton(); 77 } 78 79 public Text CreateText() 80 { 81 return new WindowsText(); 82 } 83 } 84 85 public class LinuxFactory : ComponentFactory//具体Linux控件工厂 86 { 87 public Button CreateButton() 88 { 89 return new LinuxButton(); 90 } 91 92 public Text CreateText() 93 { 94 return new LinuxText(); 95 } 96 } 97 98 public class UnixFactory : ComponentFactory//具体Unix控件工厂 99 { 100 public Button CreateButton() 101 { 102 return new UnixButton(); 103 } 104 105 public Text CreateText() 106 { 107 return new UnixText(); 108 } 109 } 110 111 class Program 112 { 113 static void Main(string[] args) 114 { 115 ComponentFactory comfactory; 116 Button button; 117 Text text; 118 //也可通过配置文件存储具体工厂名 119 comfactory = new WindowsFactory(); 120 button = comfactory.CreateButton(); 121 button.Display(); 122 123 comfactory = new LinuxFactory(); 124 button = comfactory.CreateButton(); 125 button.Display(); 126 127 comfactory = new UnixFactory(); 128 text = comfactory.CreateText(); 129 text.Display(); 130 131 } 132 } 133 } 134 }
结果:
值得注意的是,在抽象工厂模式中,增加新的产品族很容易,只需要增加具体产品并对应增加一个新的具体工厂就可以了,对已有代码不需要进行修改,但是增加新的产品等级结构很麻烦,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都必须要添加新的产品等级结构,违背了开闭原则,这种特性被称为开闭原则的倾斜性
- 抽象工厂模式的优缺点和适用环境
- 抽象工厂模式的优点:
- 隔离了具体类的生成,使得客户端不需要知道什么被创建
- 当一个产品族的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族的对象
- 抽象工厂模式增加新的产品族很容易,无需修改已有系统,符合开闭原则
- 抽象工厂模式的缺点
- 增加新的产品结构很麻烦,需要对原有系统进行大规模的修改,甚至需要修改抽象层代码,违背了开闭原则
- 抽象工厂模式的适用环境
- 当一个系统不依赖于产品类实例如何被创建、组合和表达的细节,用户无需关心对象的创建过程,将对象的创建和适用解耦
- 系统中有多于一个的产品族,但每次只需要使用其中某一个产品族,可以通过配置文件等动态地改变产品族,也很方便的增加新的产品族
- 属于同一个产品族的产品将一起使用
- 产品等级结构稳定,设计完成后,不会向系统增加i新的产品等级结构或者删除已有的产品等级结构