温故而知新:设计模式之抽象工厂(AbstractFactory)

抽象工厂主要用来解决多个系列的对象实例问题。

问题的应用场景(来源于李建忠老师的webcast讲座):

如果有一款游戏,里面有"道路,房屋,隧道,丛林"这四类基本设施,而且不同的地图(比如中国区,印度区,欧美区)这些设施的风格各有特色,比如中国区应该是中国风格,印度区可能是古典风格,欧美区可能是现代风格...

并且这些基本设施的风格还有可能会一直不断增加,作为程序员/架构师,您想如何让以后的维护/升级变得更轻松,比如新增加一种风格时,最好只要改改配置,顺便发个新的dll复制到安装目录就完事,而不是把原来的类似

xxx = new ChineseStyleRoad(),全部改成xxx = new NewStyleRoad()...

分析:OO思想中有一个重要原则,即开放封闭原则,展开来讲就是 对修改(也称变化)封闭(也称封装),而对扩展(比如在原来框架上的功能增加)开放。本例场景中的变化点,就于在基础设施风格的变化。

代码:

客户程序依赖的抽象部分

#region client程序依赖的抽象类(这些类之间彼此可能有交互)和抽象工厂,所有系列对象创建过程中的变化封装于此
    //道路
    public abstract class Road {
        public abstract void Show();
    }

    //房屋
    public abstract class Building {
        public abstract void Show();
    }

    //地道
    public abstract class Tunnel {
        public abstract void Show();
    }

    //从林
    public abstract class Jungle {
        public abstract void Show();
    }

    //客户依赖的抽象工厂
    public abstract class FacilitiesFactory 
    {
        public abstract Road CreateRoad();

        public abstract Building CreateBuilding();

        public abstract Tunnel CreateTunnel();

        public abstract Jungle CreateJungle();

    }
    #endregion

封装好变化点后,客户端程序就可以这样调用了:

客户程序

 //客户程序
    public class GameManager 
    {
        FacilitiesFactory _facilitiesFactory;
        Road _road;
        Building _building;
        Tunnel _tunnel;
        Jungle _jungle;

        public GameManager(FacilitiesFactory f) 
        {
            this._facilitiesFactory = f;
        }

        public void BuildGameFacilities() 
        {
            _road = _facilitiesFactory.CreateRoad();
            _building = _facilitiesFactory.CreateBuilding();
            _jungle = _facilitiesFactory.CreateJungle();
            _tunnel = _facilitiesFactory.CreateTunnel();
        }

        public void Run() 
        {
            _road.Show();
            _building.Show();
            _jungle.Show();
            _tunnel.Show();
        }
    }

可以看到,这里并没有任何具体类的依赖,也就是说基本解除了依赖,但不管如何抽象最终还是要得到具体类的实例,下面是具体类和工厂的实现: 

具体类和工厂的实现

  #region 具体类/工厂的实现(实际开发中,具体的某一系列对象可单独用独立项目发布成独立的程序集,以应对变化,比如增加一个新系统时,仅需要修改配置,再加一个dll就可实现批量替换所有子对象)
    #region//现代风格的road,building,tunnel,jungle及对应的工厂
    public class ModernRoad : Road 
    {
        public override void Show()
        {
            Console.WriteLine("现代风格的道路已经建成!");
        }
    }

    public class ModernBuilding : Building 
    {
        public override void Show()
        {
            Console.WriteLine("现代风格的房屋已经建成!");
        }
    }

    public class ModernTunnel : Tunnel
    {
        public override void Show()
        {
            Console.WriteLine("现代风格的隧道已经建成!");
        }
    }

    public class ModernJungle : Jungle
    {
        public override void Show()
        {
            Console.WriteLine("现代风格的丛林已经建成!");
        }
    }

    public class ModernFacilityisFactory : FacilitiesFactory 
    {
        public override Road CreateRoad() 
        {
            return new ModernRoad();
        }

        public override Building CreateBuilding()         
        {
            return new ModernBuilding();
        }

        public override Tunnel CreateTunnel() 
        {
            return new ModernTunnel();
        }

        public override Jungle CreateJungle() 
        {
            return new ModernJungle();
        }
    }
    #endregion

    #region//古典风格的road,building,tunnel,jungle及对应的工厂
    public class ClassicRoad : Road
    {
        public override void Show()
        {
            Console.WriteLine("古典风格的道路已经建成!");
        }
    }

    public class ClassicBuilding : Building
    {
        public override void Show()
        {
            Console.WriteLine("古典风格的房屋已经建成!");
        }
    }

    public class ClassicTunnel : Tunnel
    {
        public override void Show()
        {
            Console.WriteLine("古典风格的隧道已经建成!");
        }
    }

    public class ClassicJungle : Jungle
    {
        public override void Show()
        {
            Console.WriteLine("古典风格的丛林已经建成!");
        }
    }

    public class ClassicFacilityisFactory : FacilitiesFactory
    {
        public override Road CreateRoad()
        {
            return new ClassicRoad();
        }

        public override Building CreateBuilding()
        {
            return new ClassicBuilding();
        }

        public override Tunnel CreateTunnel()
        {
            return new ClassicTunnel();
        }

        public override Jungle CreateJungle()
        {
            return new ClassicJungle();
        }
    }
    #endregion

    #region//中国风格的road,building,tunnel,jungle及对应的工厂
    public class ChineseRoad : Road
    {
        public override void Show()
        {
            Console.WriteLine("中国风格的道路已经建成!");
        }
    }

    public class ChineseBuilding : Building
    {
        public override void Show()
        {
            Console.WriteLine("中国风格的房屋已经建成!");
        }
    }

    public class ChineseTunnel : Tunnel
    {
        public override void Show()
        {
            Console.WriteLine("中国风格的隧道已经建成!");
        }
    }

    public class ChineseJungle : Jungle
    {
        public override void Show()
        {
            Console.WriteLine("中国风格的丛林已经建成!");
        }
    }

    public class ChineseFacilityisFactory : FacilitiesFactory
    {
        public override Road CreateRoad()
        {
            return new ChineseRoad();
        }

        public override Building CreateBuilding()
        {
            return new ChineseBuilding();
        }

        public override Tunnel CreateTunnel()
        {
            return new ChineseTunnel();
        }

        public override Jungle CreateJungle()
        {
            return new ChineseJungle();
        }
    }
    #endregion
    #endregion

正式调用: 

代码

    class Program
    {
        static void Main(string[] args)
        {
            //注意下面的写法:
            //Assembly.Load("这是里程序集的名称")
            //CreateInstance("这是具体类的完整表示法,即:命令空间.类名")
            FacilitiesFactory _factory = (FacilitiesFactory)Assembly.Load("AbstractFactory").CreateInstance(ConfigurationManager.AppSettings["FactoryType"].ToString());

            GameManager gm = new GameManager(_factory);
            gm.BuildGameFacilities();
            gm.Run();
            Console.Read();
            
        }
    }

当然这里还有一个配置文件:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="FactoryType" value="AbstractFactory.ClassicFacilityisFactory"/>
  </appSettings>
</configuration>

可以看到,利用抽象工厂再配合反射,如果想把所有"中国风格"的设施换成"古典风格"的设施,只需要把配置文件中的<add key="FactoryType" value="AbstractFactory.ChineseFacilityisFactory"/>换成   <add key="FactoryType" value="AbstractFactory.ClassicFacilityisFactory"/>,原代码一行都不用改,是不是很轻松! 如果新增了一种风格,也只要把新增加的"具体类和工厂"所对应的程序集dll添加到程序目录下,然后修改配置文件即可,也不需要修改原来已经稳定运行的程序。

时间: 2024-08-01 01:26:18

温故而知新:设计模式之抽象工厂(AbstractFactory)的相关文章

C#设计模式之抽象工厂(AbstractFactory)

设计 1. 为什么要用抽象工厂?用抽象工厂的好处 这里我暂时还想不出有什么好处 我觉得就是利用接口来实现封装其子类,让具体的工作交给它的子类去做.所以说这应该不能算抽象工厂的优点,只能算作接口的优点. 2. 在C#中怎样用抽象工厂? 好,我们来看一下怎么来实现 比如说我们要写一个连接数据库的组件,既支持sqlserver的,又要支持oledb的,这时我们就可以用AbstractFactory设计模式了. 先定义一个接口: public interface IDbHelper { void Exe

乐在其中设计模式(C#) - 抽象工厂模式(Abstract Factory Pattern)

原文:乐在其中设计模式(C#) - 抽象工厂模式(Abstract Factory Pattern)[索引页][源码下载] 乐在其中设计模式(C#) - 抽象工厂模式(Abstract Factory Pattern) 作者:webabcd 介绍 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 示例 有Message和MessageModel,Message有一个Insert()方法,该方法的参数是MessageModel. AbstractMessageModel usi

C#设计模式(4)——抽象工厂模式

原文:C#设计模式(4)--抽象工厂模式 一.引言 在上一专题中介绍了工厂方法模式,工厂方法模式是为了克服简单工厂模式的缺点而设计出来的,简单工厂模式的工厂类随着产品类的增加需要增加额外的代码),而工厂方法模式每个具体工厂类只完成单个实例的创建,所以它具有很好的可扩展性.但是在现实生活中,一个工厂只创建单个产品这样的例子很少,因为现在的工厂都多元化了,一个工厂创建一系列的产品,如果我们要设计这样的系统时,工厂方法模式显然在这里不适用,然后抽象工厂模式却可以很好地解决一系列产品创建的问题,这是本专

设计模式之四(抽象工厂模式第三回合)

原文:设计模式之四(抽象工厂模式第三回合) 前言 抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 抽象工厂模式最大的好处便是易于交换产品系列,由于具体工厂类,例如IFactory factory=new AccessFactory(),在一个应用中只需要在初始化的时候出现一次,这就使得改变一个应用的具体工厂变得非常容易,它只需要改变具体工厂即可使用不同的产品配置.我们的设计不能去防止需要的变更,那么我们的理想便是让改动变得最小,那么现在如果你要更改数据库访问,

设计模式之四(抽象工厂模式第一回合)

原文:设计模式之四(抽象工厂模式第一回合) 前言 首先关于抽象工厂模式的学习,我们需要慢慢的,由浅入深的进入.不能单刀直入,否则可能达不到预期学明白的目标. 第一回合  首先我们从最简单的数据访问程序开始吧. 下面先来看一个简单的小例子,代码很简单 public class User { public int ID{get;set;} public string Name{get;set;} } 一个简单的实体类,也相当于在SqlServer数据库中建立了相同的数据表 public class

C++设计模式之抽象工厂模式_C 语言

问题描述 之前讲到了C++设计模式--工厂方法模式,我们可能会想到,后期产品会越来越多了,建立的工厂也会越来越多,工厂进行了增长,工厂变的凌乱而难于管理:由于工厂方法模式创建的对象都是继承于Product的,所以工厂方法模式中,每个工厂只能创建单一种类的产品,当需要生产一种全新的产品(不继承自Product)时,发现工厂方法是心有余而力不足. 举个例子来说:一个显示器电路板厂商,旗下的显示器电路板种类有非液晶的和液晶的:这个时候,厂商建造两个工厂,工厂A负责生产非液晶显示器电路板,工厂B负责生产

.NET简谈设计模式之(抽象工厂模式)

我们继续学习设计模式系列文章. 今天要讲的是设计模式中经常被用到的"工厂模式",所谓工厂模式就是将对象的创建交给一个叫做工厂的对象来统一进行处理.主要是将对象的依赖关系进行解耦,消除对象之间的直接耦合.那么工厂的使用有几种方式呢?那就要看我们对工厂的理解了,工厂是创建对象的一个逻辑名称,工厂可以是一个方法.一个静态类等等.只要起到对象的创建就能给它赋予上一个工厂的名称. 那么什么是抽象工厂呢?我想很多人对它的理解并不是很透彻,甚至有的人就觉得工厂一定要是抽象的.我表示不理解,一个抽象类

艾伟_转载:.NET设计模式:抽象工厂模式(Abstract Factory)

概述 在软件系统中,经常面临着"一系列相互依赖的对象"的创建工作:同时由于需求的变化,往往存在着更多系列对象的创建工作.如何应对这种变化?如何绕过常规的对象的创建方法(new),提供一种"封装机制"来避免客户程序和这种"多系列具体对象创建工作"的紧耦合?这就是我们要说的抽象工厂模式. 意图 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 模型图 逻辑模型: 物理模型: 生活中的例子 抽象工厂的目的是要提供一个创建一系列相关或

Head First设计模式之抽象工厂模式

一.定义 给客户端提供一个接口,可以创建多个产品族中的产品对象 ,而且使用抽象工厂模式还要满足一下条件:     1)系统中有多个产品族,而系统一次只可能消费其中一族产品.      2)同属于同一个产品族的产品以其使用.  二.结构 抽象工厂模式的各个角色(和工厂方法一样):      1)抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关.是具体工厂角色必须实现的接口或者必须继承的父类.在java中它由抽象类或者接口来实现.      2)具体工厂角色:它含有和具体业务逻辑有关的代码.