设计模式的艺术之道–抽象工厂模式
声明:本系列为刘伟老师博客内容总结(http://blog.youkuaiyun.com/lovelion),博客中有完整的设计模式的相关博文,以及作者的出版书籍推荐
本系列内容思路分析借鉴了刘伟老师的博文内容,同时改用C#代码进行代码的演示和分析(Java资料过多 C#表示默哀).
本系列全部源码均在文末地址给出。
本系列开始讲解创建型模式,顾名思义,这类模式主要是为了解决类的创建问题。
- 创建型模式(Creational Pattern)关注对象的创建过程。分析你怎么来的
- 创建型模式对类的实例化过程进行了抽象,对用户隐藏了类的实例的创建细节。客户不知道你怎么来的
- 创建型模式描述如何将对象的创建和使用分离,让用户在使用对象时无须关心对象的创建细节。你用就行,别管我怎么来的。
- 创建型模式关注点 创建什么(What) 由谁创建(Who) 何时创建(When)
6种常见的创建型模式
抽象工厂模式
工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。此时,我们可以考虑将一些相关的产品组成一个“产品族”,由同一个工厂来统一生产。
1.1定义
- 抽象工厂模式 (Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。
- 老板规模更大了,大饭店包含川菜,粤菜,湘菜(工厂)好几个品种,满足不同地域的客户的口味特色菜(产品)需求。
- 抽象工厂模式中的具体工厂不只是创建一种产品,它负责创建一族产品。
1.2情景实例
问题描述
- 界面皮肤库设计
菜鸟软件公司欲开发一套界面皮肤库,可以对桌面软件进行界面美化。为了保护版权,该皮肤库源代码不打算公开,而只向用户提供已打包好的库文件。用户在使用时可以通过菜单来选择皮肤,不同的皮肤将提供视觉效果不同的按钮、文本框、组合框等界面元素,其结构示意图如图1所示
该皮肤库需要具备良好的灵活性和可扩展性,用户可以自由选择不同的皮肤,开发人员可以在不修改既有代码的基础上增加新的皮肤。
初步思路
使用工厂方法模式进行系统的设计,为了保证系统的灵活性和可扩展性,提供一系列具体工厂来创建按钮、文本框、组合框等界面元素,客户端针对抽象工厂编程。
现有缺点(未来变化)
- (1) 当需要增加新的皮肤时,虽然不要修改现有代码,但是需要增加大量类,配套的类(红色框 框又有好几种)
- (2)针对每一个新增具体组件都需要增加一个具体工厂,类的个数成对增加,这无疑会导致系统越来越庞大
- (3) 用户使用时需要进行大量的判断,客户端代码和配置文件都较为复杂。
如何改进
引入抽象工厂模式
- 希望一个工厂可以提供多个产品对象,而不是单一对象,如一个电器工厂,它可以生产电视机、电冰箱、空调等多种电器
- 工厂生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构、属于不同类型的具体产品时就可以使用抽象工厂模式
- 抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式需要面对多个产品等级结构。
关键概念解释
- 产品等级结构:产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。(同一产品的不同品牌)
- 产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中,海尔电视机、海尔电冰箱构成了一个产品族。(一系列的同品牌产品)
UML类图
实例关键代码
namespace AbstractFactory
{
interface SkinFactory
{
Button CreateButton();
TextField CreateTextField();
ComboBox CreateComboBox();
}
interface Button
{
void Display();
}
class SummerButton : Button
{
public void Display()
{
Console.WriteLine("显示浅蓝色按钮。");
}
}
class SpringButton : Button
{
public void Display()
{
Console.WriteLine("显示浅绿色按钮。");
}
}
//中间类似代码略
class SpringSkinFactory : SkinFactory
{
public Button CreateButton()
{
return new SpringButton();
}
public TextField CreateTextField()
{
return new SpringTextField();
}
public ComboBox CreateComboBox()
{
return new SpringComboBox();
}
}
class Program
{
static void Main(string[] args)
{
//使用抽象层定义
SkinFactory factory;
Button bt;
TextField tf;
ComboBox cb;
//读取配置文件
string factoryType = ConfigurationManager.AppSettings["factory"];
//反射生成对象
factory = (SkinFactory)Assembly.Load("AbstractFactory").CreateInstance(factoryType);
bt = factory.CreateButton();
tf = factory.CreateTextField();
cb = factory.CreateComboBox();
bt.Display();
tf.Display();
cb.Display();
Console.Read();
}
}
}
1.3模式分析
动机和意图
- 在简单工厂模式中,所有的产品都由同一个工厂创建,工厂类职责较重
- 具体产品与工厂类之间的耦合度高,严重影响了系统的灵活性和扩展性
一般结构
- 工厂方法模式包含如下角色:
- AbstractFactory:抽象工厂 对子工厂的抽象归类
- AbstractProduct:抽象产品 对产品的抽象归类提升
- ConcreteProduct:具体产品角色 工厂输出的产品
- ConcreteFactory : 具体工厂 生产具体产品的具体工厂
改进的优点
- 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建
- 它能够保证客户端始终只使用同一个产品族中的对象(同一个风格或者系列)
- 增加新的产品族很方便,无须修改已有系统,符合“开闭原则
现存的缺点
- 增加产品族(一个新的系列或者品牌):对于增加新的产品族,抽象工厂模式很好地支持了“开闭原则”,只需要增加具体产品并对应增加一个新的具体工厂,对已有代码无须做任何修改。
- 增加新的产品等级结构(一个新的未存在的物品):对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,违背了“开闭原则”。
适用场景
(1) 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节
(2) 系统中有多于一个的产品族(系列 品牌),而每次只使用其中某一产品族。
(3) 同一个产品族(品牌)的产品将在一起使用,这一约束必须在系统的设计中体现出来。
举例:小王去国际大酒店吃饭(里边有川菜 粤菜 湘菜等) 电脑品牌机的组装(华硕联想 可能有一天突然屏幕换成了空间触摸的 所有电脑都得换)
实例源代码
GitHub地址
百度云地址:链接: https://pan.baidu.com/s/1hsjFNEW 密码: ms9w
本文深入探讨了抽象工厂模式的概念及其实现方式,介绍了该模式如何解决简单工厂模式中工厂类职责过重的问题,并通过C#代码示例展示了如何应用于界面皮肤库设计中,实现了灵活且易于扩展的系统。
1416

被折叠的 条评论
为什么被折叠?



