目录
2)当一个产品族中的多个对象被设计成一起工作,它能够保证客户端始终只使用同一产品族中的对象
1)一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节
2)系统中有多于一个的产品族,但是每次只使用其中一个产品族,可以通过配置文件等方式使得用户能够动态改变产品族
3)属于同一产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来
4)产品等级结构稳定,设计完成不会向系统增加新的产品等级结构或者删除已有的产品等级结构
在工厂方法模式中,每一个具体工厂只需要生产一种具体产品,但是在抽象工厂模式中,一个具体工厂可以生产一组相关的具体产品,这样的一组产品称为产品族,产品族中的每一个产品都分属于某一个产品继承等级结构。
一、产品等级结构与产品族
1:产品等级结构
产品等级结构即产品的继承结构,例如一个抽象类时电视机,其子类包括海尔电视及、TCL电视机等,则抽象电视机和具体品牌的电视机之间构成了一个产品的等级结构,抽象电视机是父类,具体品牌的电视机是子类
2:产品族
在抽象工厂模式中,产品族是指同一个工厂生产的,位于不同产品等级结构中的一组产品。例如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中,海尔电视机、电冰箱构成了一个产品族。
只要指明了一个产品所处的产品族和等级结构,就可以唯一确认产品。
二、抽象工厂模式概述
学习难度:⭐⭐⭐⭐ 使用频率:⭐⭐⭐⭐⭐
定义:提供一个创建一些列相关或互相依赖对象的接口,而无须指定它们的类,工厂模式又成工具(Kit)模式
当一个工厂等级模式可以创建分属不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单,有效率
三、抽象工厂模式的结构和实现
1:抽象工厂模式的结构
1)AbstractFactory(抽象工厂)
它声明了一组用于创建一族产品的方法,每个方法对应一个产品
2)ConcrreteFactory(具体工厂)
它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族,每个产品都位于某个产品等级结构中
3)AbstractProduct(抽象产品)
它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法
4)ConcreteProduct(具体产品)
它定义具体工厂所生产的具体产品对象,实现抽象产品中声明的业务方法
2:抽象工厂模式的实现
在抽象工厂中声明多个工厂方法,用于创建不同类型的产品,抽象工厂可以是接口,也可以是抽象类或者具体类,典型代码如下:
abstract class abstractFactory
{
public abstract AbstractProductA CreateProductA(); //工厂方法一
public abstract AbstractProductB CreateProductB(); //工厂方法二
}
具体工厂实现抽象工厂,每一个具体工厂方法创建一个特定的产品对象,而同一个具体工厂所创建的产品对象构成了一个产品族。对于每一个具体工厂,代码如下:
class ConcrereFactory1:AbstractFactory
{
//工厂方法一的实现
public override AbstractProductA CreateProductA()
{
return new ConcrereProductA1();
}
//共产方法二的实现
public override AbstractProductB CreateProductB()
{
return new ConcrereProductB1();
}
}
四、抽象工厂模式的应用实例
在之前的博客中,也有写到抽象工厂模式,详见:
零基础自学C#——Part5:委托和设计模式_代码历险记的博客-CSDN博客
下面通过另一个实例来学习,需求如下:
某软件公司要开发一套界面皮肤库,可以基于.NET平台的桌面软件进行界面美化,用户在使用时可以通过菜单来选择皮肤,不同的皮肤将提供视觉效果不同的按钮、文本框、组合框等界面元素,例如春天(Spring)皮肤将提供浅绿色、绿色等UI组合,夏天(Summer)将提供各种蓝色的UI组合。
Spring风格:浅绿色按钮、绿色边框的文本框、绿色边框的组合框
Summer风格:浅蓝色按钮、蓝色边框的文本框、蓝色边框的组合框
开发人员可以在不修改既有代码的基础上增加新的皮肤
SkinFactory接口充当抽象工厂
namespace AbstractFactorySample
{
interface SkinFactory
{
Button CreateButton();
TextField CreateTextField();
ComboBox CreateComboBox();
}
}
子类SpringSkinFactory和SummerSkinFactory充当具体工厂
namespace AbstractFactorySample
{
class SpringSkinFactory: SkinFactory
{
public Button CreateButton()
{
return new SpringButton();
}
public TextField CreateTextField()
{
return new SpringTextField();
}
public ComboBox CreateComboBox()
{
return new SpringComboBox();
}
}
}
namespace AbstractFactorySample
{
class SummerSkinFactory: SkinFactory
{
public Button CreateButton()
{
return new SummerButton();
}
public TextField CreateTextField()
{
return new SummerTextField();
}
public ComboBox CreateComboBox()
{
return new SummerComboBox();
}
}
}
接口Button、TextField和ComboBox充当抽象产品
namespace AbstractFactorySample
{
interface Button
{
void Display();
}
}
namespace AbstractFactorySample
{
interface TextField
{
void Display();
}
}
namespace AbstractFactorySample
{
interface ComboBox
{
void Display();
}
}
子类SpringButton、SpringTextField、SpringComboBox充当具体产品
namespace AbstractFactorySample
{
class SpringButton:Button
{
public void Display()
{
Console.WriteLine("显示浅绿色按钮");
}
}
}
namespace AbstractFactorySample
{
class SpringTextField:TextField
{
public void Display()
{
Console.WriteLine("显示绿色边框的文本框");
}
}
}
namespace AbstractFactorySample
{
class SpringComboBox:ComboBox
{
public void Display()
{
Console.WriteLine("显示绿色边框的组合框");
}
}
}
SunmmerButton、SummerTextField、SummerComboBox充当具体产品
namespace AbstractFactorySample
{
class SummerButton:Button
{
public void Display()
{
Console.WriteLine("显示浅蓝色按钮");
}
}
}
namespace AbstractFactorySample
{
class SummerTextField:TextField
{
public void Display()
{
Console.WriteLine("显示蓝色边框的文本框");
}
}
}
namespace AbstractFactorySample
{
class SummerComboBox:ComboBox
{
public void Display()
{
Console.WriteLine("显示蓝色边框的组合框");
}
}
}
配置文件App.config:在配置文件中存储了具体工厂类类名。
<?xml version = "1.0" encoding = "utf - 8"?>
<configuration>
<appSettings>
<add key ="factory"value="AbstractFactorySample.SpringSkinFactory"/>
</appSettings>
</configuration>
客户端测试:
using System;
using System.Configuration;
using System.Reflection;
namespace AbstractFactorySample
{
class Program
{
static void Main(string[]args)
{
//使用抽象层定义
SkinFactory factory;
Button bt;
TextField tf;
ComboBox cb;
//读取配置问加你
string factoryType= ConfigurationManager.AppSettings["factory"];
//反射生成对象
factory=(SkinFactory)Assembly.Load("AbstractFactorySample").CreateInstance(factoryType);
bt=factory.CreateButton();
tf=factory.CreateTextField();
cb=factory.CreateComboBox();
bt.Display();
tf.Display();
cb.Display();
Console.Read();
}
}
}
编译并运行程序,输出结果如下:
显示浅绿色的边框。
显示绿色边框的文本框
显示绿色边框的组合框
如果需要更换皮肤,只需修改配置文件即可,如需将春天风格改为夏天风格,只需要修改:
<?xml version = "1.0" encoding = "utf - 8"?>
<configuration>
<appSettings>
<add key ="factory"value="AbstractFactorySample.SummerSkinFactory"/>
</appSettings>
</configuration>
重新运行客户端程序,得到:
显示浅蓝色的边框。
显示蓝色边框的文本框
显示蓝色边框的组合框
五、开闭原则的倾斜性
抽象工厂模式中,增加新的产品族很方便,但是增加新的产品等级结构很麻烦,抽象工厂的这种特性称为开闭原则的倾斜性。开闭原则要求系统对扩展开放,对修改关闭,通过拓展达到增强其功能的目的,对于涉及多个产品族和多个产品的等级结构的系统,其功能增强包括两个方面。
1:增加产品族:新增产品族对于抽象工厂而言,只需增加具体产品并对应增加一个新的具体工厂即可,对已有代码无需做任何修改。
2:增加新的产品等级结构:需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,违背开闭原则。