设计模式 - 抽象工厂模式

本文深入探讨了抽象工厂设计模式的概念、适用场景、结构与实现方式,并分析了其优点与局限性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 意图

提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。

别名 Kit


设计模式一书中这个模式作为创建型模式的第一个模式出现,但是这个模式本身和Singleton(单例), Factory Method(工厂方法) 又有一定的关联性,所以建议可以先看这个模式,在看完单例和工厂方法模式后再回头看一遍抽象工厂会比较好。

重点在于“一系列“这三个字,同时这些对象是”相关或相互依赖的“,作者举了一个多视感标准的用户界面工具包的例子,光从意图的字面含义上就很容易能够理解这个模式的用途,一个用户界面工具包包含了很多种控件(组件),这些组件有一定的风格(Style)因此他们是相关的,抽象工厂定义了一个抽象的接口去创建他们,从调用者的角度来讲很好的满足了依赖倒置原则。


2. 适用性

在以下情况可以使用Abstract Factory模式

一个系统要独立于它的产品的创建,组合和表示时

一个系统要由多个产品系列中的一个来配置时

当你要强调一系列相关的产品对象的设计以便进行联合使用时

当你提供一个产品类库,而只想显示它们的接口而不是实现时


这部分内容很好的反映了抽象工厂与其他模式之间的区别,第一是使用某个产品系列来配置系统,第二产品系列里的产品对象需要联合使用

我突然想到一个问题:如果有一个支持多数据库的系统,数据访问层的设计为什么无法用到抽象工厂?

SqlConnection, SqlCommand, SqlParameter, SqlAdapter可以认为是一系列相关的类,但是我们很难说用这些类去“配置”一个系统


有一些场景倒是和产品系列和配置有点相关,例如

装修一个房子,有中式和西式两种风格,对应不同的风格墙面的颜色,吊顶的设计,瓷砖的选择,厨房卫生间的整体风格都要一致,每部分的选材可以认为是一系列相关的对象,同时他们一起可以装饰(配置)我的房子

另一个例子是电脑的组装,电脑是系统,其中的零配件是具体的产品,而诸如“家用型电脑”,“商务办公型”,"游戏娱乐型“ 可以认为是不同的产品系列(ConcreteFactory)


3. 结构




4. 效果

在看具体代码前先看下设计模式一书中的概括

1) 它分离了具体的类

2)它使得易于交换产品系列

3)它有利于产品的一致性

4)难以支持新种类的产品


5. 实现

根据抽象工厂的特点,很容易想到将具体工厂实现为一个单例

另外在创建具体产品类时,可以采用简单工厂方法(Simple Factory)

    class Program
    {
        static void Main(string[] args)
        {
            AbstractFactory factory = AbstractFactory.Instance("1");
            AbstractProductA productA = factory.CreateProductA();
            AbstractProductB productB = factory.CreateProductB();
            //call product a and product b methods to do something
        }
    }

    class FactoryConfig
    {
        public static int type;
    }

    abstract class AbstractFactory
    {
        private static AbstractFactory _instance = null;

        public abstract AbstractProductA CreateProductA();
        public abstract AbstractProductB CreateProductB();

        protected AbstractFactory()
        { 
        }

        public static AbstractFactory Instance()
        {
            if (_instance == null)
            {
                if (FactoryConfig.type == 1)
                    _instance = new ConcreteFactory1();
                else if (FactoryConfig.type == 2)
                    _instance = new ConcreteFactory2();
                else
                    throw new NotImplementedException();
            }
            return _instance;
        }
    }

    class ConcreteFactory1 : AbstractFactory
    {
        public override AbstractProductA CreateProductA()
        {
            return new ProductA1();
        }

        public override AbstractProductB CreateProductB()
        {
            return new ProductB1();
        }
    }

    class ConcreteFactory2 : AbstractFactory
    {
        public override AbstractProductA CreateProductA()
        {
            return new ProductA2();
        }

        public override AbstractProductB CreateProductB()
        {
            return new ProductB2();
        }
    }

    abstract class AbstractProductA
    { 
    }

    abstract class AbstractProductB
    { 
    }

    class ProductA1 : AbstractProductA
    { 
    }

    class ProductA2 : AbstractProductA
    { 
    }

    class ProductB1 : AbstractProductB
    { 
    }

    class ProductB2 : AbstractProductB
    { 
    }



注意上面的例子中 AbstractFactory类实现了一个单例,Instance 方法内部根据某个全局变量去创建ConcreteFactory


6. 缺点

很明显,当有新的产品系列出现时这个结构无法满足开放封闭原则

通俗的说就是当我们有中式,西式的装修风格,如果增加一种宫廷式装修风格那么势必增加很多类并且修改AbstractFactory

设计模式一书提出了可扩展的抽象工厂,个人认为这不是一个好主意(当然你可以通过传参数通过反射来实现)

设计无法做到完美,虽然增加产品系列会导致一系列的变化,但是好处是这个变化本身必须遵循这套结构,本质上不会增加什么复杂度,所以不必苛求


7. 扩展

上面的例子具体产品的对象创建没有用到工厂方法(Factory Method),既然抽象工厂涉及到的一系列产品是相关的,那么他们的创建也许就不像上面代码那样那么简单了

对于复杂对象的创建也许就要用到其他的设计模式了

### 抽象工厂模式概述 抽象工厂模式是一种创建型设计模式,其核心在于提供了一种方式来创建一系列相关或相互依赖的对象,而不必指定它们的具体类[^2]。通过这种方式,客户端能够使用统一的接口来获取所需的产品实例,从而降低了系统组件之间的耦合度。 #### 模式的结构与工作原理 该模式主要由四个部分组成: - **抽象工厂(Abstract Factory)**:定义了一个用于创建一族具体产品对象的方法集合。 - **具体工厂(Concrete Factory)**:实了抽象工厂所声明的操作,负责生产特定种类的产品系列。 - **抽象产品(Abstract Product)**:为每一种可能被生产的物品定了通用接口。 - **具体产品(Concrete Product)**:实际要创建出来的实体类,继承自相应的抽象产品并实其功能。 当客户请求某个类型的对象时,会调用相应工厂里的方法得到想要的结果;由于整个过程中只涉及到高层模块对于低层模块的引用(即仅知道如何操作抽象级别的成员),因此即使内部逻辑发生变化也不会影响到外部使用者。 #### 应用场景分析 此模式非常适合应用于以下情况: - 当应用程序存在多个可互换的产品线,并希望保持独立性以便于扩展新特性时不破坏有代码; - 需要在运行期间动态决定应该采用哪一套计方案来进行构建; - 要求确保同一版本下的各个组成部分始终一致地协同运作。 例如,在图形库中可以根据不同的渲染引擎选择合适的形状绘制器(如OpenGL vs DirectX)。再比如操作系统风格切换工具里根据不同主题调整窗口控件外观等都是很好的例子。 #### Java实案例展示 下面给出一段简单的Java代码片段用来说明上述概念的应用: ```java // 定义两个层次的产品接口 public interface GUIFactory { Button createButton(); } public interface Button { void paint(); } ``` 接着分别针对Windows和MacOS平台定制化各自的GUI元素: ```java // Windows风格按钮 class WinButton implements Button { public void paint() { System.out.println("Render a button in the Windows style."); } } // MacOS风格按钮 class MacButton implements Button { public void paint() { System.out.println("Render a button in the macOS style."); } } ``` 最后建立对应的工厂类完成最终组装: ```java // 创建适用于Windows系统的UI部件制造者 class WinFactory implements GUIFactory { @Override public Button createButton() { return new WinButton(); } } // 创建适用于macOS系统的UI部件制造者 class MacFactory implements GUIFactory { @Override public Button createButton() { return new MacButton(); } } ``` 这样就可以很容易地根据当前环境配置选取适当的主题样式了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值