我的设计模式之旅(3)――抽象工厂模式AbstractFactory

抽象工厂模式,花了一些时间来学习它,它的意图就是“提供一个接口,让该接口负责创建一系列相关或者相互依赖的对象,无需指定它们具体的类”,对于已有系列对象的创建时,根据需要替换起来很方便。但是对于新增系列对象的替换则还是需要像原来一样,最起码要新增加这个我们需要的新类,但是这种良好的结构为我们提供了很方便的扩展方法。个人感觉它的缺点就是不能创建有着不同个数对象的系列,不过应该是可以通过工厂方法来解决的,这个留做以后解决的问题。
看到很多相关文章最后都是付诸于代码的实现,自己感觉 TerryLee 的就比较好,设计模式设计模式,当然是设计的模式,不是代码的模式。应该是让我们有好的设计,最后代码只是设计的具体表现,让我们的代码看起来更具模块化,相互之间的耦合度更低。
实现设计和实现编码是两个过程,网上写了这么多例子,应该能看出来用来实现一个模式的编码不是一个固定的编码结构,其中可能会有这样那样的变化,但是根据具体项目的需求实现了目的,我认为就是实现了我们的设计。
引一个 吕震宇 老师文章里很能说明问题的图:
我的设计模式之旅(3)――抽象工厂模式AbstractFactory_第1张图片
 
我们就是要实现提供一个 AbstractFactory 接口来实现系列对象的创建,至于对象怎样创建,他们之间体关系是怎样实现的都不需要客户程序来关心,客户程序需要做的就是使用这个接口就得到了它需要的一系列对象。
上周末在和大家讨论的时候,被问道“最后即使是改一处还是需要修改代码啊?而且对于系列产品的创建为什么不写成一个接口?”,第二个问题比较好解答,因为像我前面说的实现不是一个固定的代码结构。第一个问题在我看了 TerryLee 的文章后得到了解决,两种方案,一种是将这种修改放到配置文件中,实现运行时的维护,另一种就是利用一个反射的机制来实现,在以后进行扩展时扩展者,甚至都不需要知道源代码,只需要提供给扩展者相应的接口即可实现扩展(厚厚~~~这里很佩服 TerryLee 的这些思考!很受用!)。
这里我也不想自己再写什么实际应用的例子,尽是对自己学习的一个总结吧,将 李建忠 老师的例子结合 TerryLee 的方案,将其再修改完善一下而已,仅是自己的一个练习吧。
首先是我们构建的工厂方法的代码,将其贴在下面。
     // 道路
     public abstract class Road
     {
     }
     // 房屋
     public abstract class Building
     {
     }
     // 地道
     public abstract class Tunnel
     {
     }
     // 丛林
     public abstract class Jungle
     {
     }
 
     public abstract class FacilitiesFactory
     {
         public abstract Road CreateRoad();
         public abstract Building CreateBuilding();
         public abstract Tunnel CreateTunnel();
         public abstract Jungle CreateJungle();
     }
 
     // 现代风格道路
     public class ModernRoad : Road
     {
     }
     // 现代风格房屋
     public class ModernBuilding : Building
     {
     }
     // 现代风格地道
     public class ModernTunnel : Tunnel
     {
     }
     // 现代风格丛林
     public class ModernJungle : Jungle
     {
     }
 
     // 现代风格
     public class ModernFacilitiesFactory : 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();
         }
     }
 
     // 古典风格道路
     public class ClassicRoad : Road
     {
     }
     // 古典风格房屋
     public class ClassicBuilding : Building
     {
     }
     // 古典风格地道
     public class ClassicTunnel : Tunnel
     {
     }
     // 古典风格丛林
     public class ClassicJungle : Jungle
     {
     }
 
     // 古典风格
     public class ClassicFacilitiesFactory : 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();
         }
     }
 
     class GameManager
     {
         FacilitiesFactory facilitiesFactory;
 
         Road road;
         Building building;
         Tunnel tunnel;
         Jungle jungle;
 
         public GameManager(FacilitiesFactory facilitiesFactory)
         {
              this.facilitiesFactory = facilitiesFactory;
         }
 
         public void BuildGameFacilities()
         {
              road = facilitiesFactory.CreateRoad();
 
              building = facilitiesFactory.CreateBuilding();
 
              tunnel = facilitiesFactory.CreateTunnel();
 
              jungle = facilitiesFactory.CreateJungle();
         }
 
         public void Run()
         {
//            road.AAA();
//            building.BBB(road);
//            tunnel.CCC();
//            jungle.DDD(tunnel);
              Console.WriteLine(road);
              Console.WriteLine(building);
              Console.WriteLine(tunnel);
              Console.WriteLine(jungle);
         }
     }
这是 李建忠 老师的例子,具体的应用客户程序如下。
         public static void Main ()
         {
              GameManager g = new GameManager(new ModernFacilitiesFactory());
              g.BuildGameFacilities();
              g.Run();
         }
这里提一下其中 GameManager g = new GameManager(new ModernFacilitiesFactory()); 这句话其实是两句合在一起写的,分开如下:
              FacilitiesFactory f = new ModernFacilitiesFactory();
              GameManager g = new GameManager(f);
TerryLee 的第一种改造就是在系列对象不发生系列添加的情况下,使用配置文件来进行例子中场景风格的替换。添加一个 App.config 文件,在其中加入风格设置的字段。
<? xml version ="1.0" encoding ="utf-8" ?>
< configuration >
         <appSettings>
              <add key="factoryName" value="ModernFacilitiesFactory"></add>
         </appSettings>
</ configuration >
然后,在代码中读取这个配置字段,根据配置字段的值来做实现。首先实现一个构建方法,然后再在客户程序中调用。
         public static FacilitiesFactory GetInstance()
         {
              string factoryName = ConfigurationSettings.AppSettings["factoryName"];
              FacilitiesFactory f;
              switch(factoryName)
              {
                   case "ModernFacilitiesFactory":
                       f = new ModernFacilitiesFactory();
                       break;
                   case "ClassicFacilitiesFactory":
                       f = new ClassicFacilitiesFactory();
                       break;
                   default:
                       f = null;
                       break;
              }
          
              return f;
         }
         // 客户程序
         public static void Main ()
         {
              GameManager g = new GameManager(GetInstance());
              //GameManager g = new GameManager(new ModernFacilitiesFactory());
              g.BuildGameFacilities();
              g.Run();
         }
其实还有一种需求就是扩展新的系列对象,如果还是不需要对客户程序进行维护,而仅是添加了新的系列对象的类,那将是很舒服的一件事。这样我们就可以通过添加 DLL 并配合配置文件的使用,就能在不修改源程序代码的情况下,扩展出我们需要的新的系列对象(这里很佩服 TerryLee 的这种实现)。
         public staticFacilitiesFactory GetInstance()
         {
              string factoryName = ConfigurationSettings.AppSettings["factoryName"];
              FacilitiesFactory f;
              if(factoryName != "")
                   f = (FacilitiesFactory)Assembly.Load(factoryName).CreateInstance(factoryName);
              else
                   f = null;
              return f;
         }
这样,我们在扩展时仅需将扩展的 DLL 放在相应的路径下并配合配置文件即实现了我们的扩展。
 

本文出自 “努力学习的小熊” 博客,转载请与作者联系!

你可能感兴趣的:(模式,职场,设计,工厂,休闲)