zoukankan      html  css  js  c++  java
  • c# 抽象工厂模式

    c# 抽象工厂模式

     

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

    image

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

    产品族:

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

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

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

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

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

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

    再来看衣服详细的类图

    image

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    先来展现一下具体的类图

    image

    上面的类图呢,说明的是有两个具体工厂,一个是 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(); 
            } 
        } 
    }

    image

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

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

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

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

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

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

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

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

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

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

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

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

  • 相关阅读:
    SD卡的控制方法(指令集和控制时序)
    MDK的优化应用(转)
    SD卡的SPI模式的初始化顺序(转)
    SD卡读写扇区注意事项(转)
    MDK下调试时提示AXF文件无法导入的解决方法(转)
    把一个 int 数字 n 格式化成16进制的字符串(前面补零成0位)
    DB9 公头母头引脚定义及连接、封装
    RS232 DB9 公头 母头 串口引脚定义
    Codeforces 91C Ski Base 加边求欧拉回路数量
    Cocos Code IDE + Lua初次使用FastTiledMap的坑
  • 原文地址:https://www.cnblogs.com/HKKD/p/7007172.html
Copyright © 2011-2022 走看看