首页 > 代码库 > c# 抽象工厂模式

c# 抽象工厂模式

先来看抽象工厂的大体的结构图

技术分享

要想明白上面的这幅类图的话,先必须要明确一个概念,

产品族:

在上面的产品列表中呢,有两个产品族,一个是“具体产品A--1”和”具体产品B--1“组成的一个族,

还有一个是“具体产品A--2”和“具体产品B--2”组成的一个族。

产品族就是在不同产品等级结构中,功能相关联的产品组成的家族。

下面就来介绍抽象工厂了(有些内容生涩的话,可以看完 Demo 后回过头来浏览)

下面给出的是抽象工厂的定义:

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

再来看衣服详细的类图

技术分享

其实从上面这副类图中可以看出,每一个具体的工厂,它都只负责创建一个产品族中的产品的实例,

从抽象工厂中派生出的具体工厂,这些具体工厂产生相同的产品(这些产品都继承自同一父类),

比如,ConcreteFactory1 和 ConcreteFactory2 中的 CreateProductA 这个方法都是产生 AbstractProductA 这种类型的产品,

但是产品的实现却是不同的,比如 ConcreteFactory1 中的 CreateProductA 实现的是产生一个 ConcreteProductA—1 产品,

而 ConcreteFactory2 中的 CreateProductA 实现的是产生一个 ConcreteProductA—2 产品,

总的来说就是不同的具体工厂产生不同的产品族,

而抽象工厂则是定义一个负责创建一组产品(也就是一个产品族)的接口,

比如上面的类图中只存在两个产品族,所以在抽象工厂中便只需要定义两个接口就可以了。

下面来剖析一下抽象工厂的优点和缺点

抽象工厂的最大好处在于交换产品系列非常方便,由于具体工厂类在一个应用中只需要在初始化的时候出现一次,

这样就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置,

比如,我在应用中本来使用的是工厂 ConcreteFactory1 来生成的产品族 1 ,

而现在需求改变了,不再使用产品族 1 ,而必须使用产品族 2 时,

此时,只需要在客户端代码中初始化 ConcreteFactory1 的位置,

把 ConcreteFactory1 改为 ConcreteFactory2 就可以了,这样就成功的将产品族1 切换到了使用产品族2 上面来,

其次,抽象工厂让具体的创建实例过程与客户端分离,客户端是通过他们的抽象接口操纵实例,

产品的具体类名也被具体工厂的实现分类,不会出现在客户端代码中。

这一点上的话,简单工厂和工厂方法也做得很不错,即依赖于抽象。

同时,如果需求需要扩展的话,比如,要重新增加一个产品族,这也很好办,

只需要增加一个具体工厂,然后增加产品族就可以了,

总之是,抽象工厂很好的遵循了开--闭原则和依赖倒置原则。

下面就来看一个 Demo ,从这个 Demo 中看出抽象工厂的优点

先来展现一下具体的类图

技术分享

上面的类图呢,说明的是有两个具体工厂,一个是 Linux 控件的制造,还有一个是 Windows 控件的制造,

然后,有两个产品族,一个是 WindowsTextBox 和 LinuxTextBox 组成的 TextBox 产品族,

还有一个就是 WindowsButton 和 LinuxButton 组成的 Button 产品族。

下面就来写类了

先来看工厂类吧

namespace AbstractFactory 

    public abstract class AbstractFactory 
    { 
        //在抽象工厂中,应该包含所有产品创建的抽象方法 
        public abstract Button CreateButton(); 
        public abstract TextBox CreateTextBox(); 
    } 
}

 

namespace AbstractFactory 

    public class WindowsFactory:AbstractFactory 
    { 
        public override Button CreateButton() 
        { 
            return new WindowsButton(); 
        }

        public override TextBox CreateTextBox() 
        { 
            return new WindowsTextBox(); 
        } 
    } 
}

 

namespace AbstractFactory 

    public class LinuxFactory:AbstractFactory 
    { 
        public override Button CreateButton() 
        { 
            return new LinuxButton(); 
        }

        public override TextBox CreateTextBox() 
        { 
            return new LinuxTextBox(); 
        } 
    } 
}

下面就给出所有的产品类

namespace AbstractFactory 

    public abstract class Button 
    { 
        public abstract void DisplayButton(); 
    } 
}

 

using System;

namespace AbstractFactory 

    class LinuxButton:Button 
    { 
        public override void DisplayButton() 
        { 
            Console.WriteLine("我的类型是:{0}", 
                this.GetType().ToString()); 
        } 
    } 
}

 

using System;

namespace AbstractFactory 

    class WindowsButton : Button 
    { 
        public override void DisplayButton() 
        { 
            Console.WriteLine("我的类型是:{0}", 
                this.GetType().ToString()); 
        } 
    } 
}

 

namespace AbstractFactory 

    public abstract class TextBox 
    { 
        public abstract void DisplayTextBox(); 
    } 
}

 

using System;

namespace AbstractFactory 

    class LinuxTextBox : TextBox 
    { 
        public override void DisplayTextBox() 
        { 
            Console.WriteLine("我的类型是:{0}", 
                this.GetType().ToString()); 
        } 
    } 
}

 

using System;

namespace AbstractFactory 

    class WindowsTextBox:TextBox 
    { 
        public override void DisplayTextBox() 
        { 
            Console.WriteLine("我的类型是:{0}", 
                this.GetType().ToString()); 
        } 
    } 
}

上面就是整个 Demo 的类了,下面就是看一下 Main 函数和效果了

using System; 
using AbstractFactory;

namespace AbstractFactoryTest 

    class Program 
    { 
        static void Main(string[] args) 
        { 
            AbstractFactory.AbstractFactory factory; 
            Button button; 
            TextBox textBox;

           //Windows 下操作 
            factory = new WindowsFactory(); 
            button = factory.CreateButton(); 
            textBox = factory.CreateTextBox(); 
            button.DisplayButton(); 
            textBox.DisplayTextBox();

            Console.WriteLine();

            //Linux 下操作 
            factory = new LinuxFactory(); 
            button = factory.CreateButton(); 
            textBox = factory.CreateTextBox(); 
            button.DisplayButton(); 
            textBox.DisplayTextBox();

            Console.ReadLine(); 
        } 
    } 
}

技术分享

从上面 Main 函数来看的话,如果你的系统本来是基于 Linux 的话,你只需更改一行代码

factory = new WindowsFactory(); 
即可实现将系统更改为 Windows ,

抽象工厂在这种情况下是非常有用的,比如,如果要实现后台数据库从 Oracle 转换到 Sql Server,

则采用抽象工厂的思想实现是最好的。

下面总结一下抽象工厂的优缺点

首先,抽象工厂的话,其可以更加方便的实现交换一个产品系列,

就像上面的 Demo 中可以轻易的实现从 Linux 上转换为 Windows,

同时,客户端代码中依赖的是抽象,而非具体的实现,

但是,抽象工厂也是有缺点的,其实这个缺点也很明显,那就是显得过于臃肿,

上面的 Demo 尽管还只有两个产品族,类图就显得有些难看了,

如果产品族一多的话,那么总的类数是成几倍的增加,这样使整个结构变得过于复杂,

类的结构也会变得更为庞大。

c# 抽象工厂模式