设计模式的艺术之道--抽象工厂模式

本文深入探讨了抽象工厂模式的概念及其实现方式,介绍了该模式如何解决简单工厂模式中工厂类职责过重的问题,并通过C#代码示例展示了如何应用于界面皮肤库设计中,实现了灵活且易于扩展的系统。

设计模式的艺术之道–抽象工厂模式

声明:本系列为刘伟老师博客内容总结(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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值