我的设计模式之旅(3)——抽象工厂模式AbstractFactory
2006-08-02 17:33 努力学习的小熊 阅读(885) 评论(0) 编辑 收藏 举报抽象工厂模式,花了一些时间来学习它,它的意图就是“提供一个接口,让该接口负责创建一系列相关或者相互依赖的对象,无需指定它们具体的类”,对于已有系列对象的创建时,根据需要替换起来很方便。但是对于新增系列对象的替换则还是需要像原来一样,最起码要新增加这个我们需要的新类,但是这种良好的结构为我们提供了很方便的扩展方法。个人感觉它的缺点就是不能创建有着不同个数对象的系列,不过应该是可以通过工厂方法来解决的,这个留做以后解决的问题。
看到很多相关文章最后都是付诸于代码的实现,自己感觉TerryLee的就比较好,设计模式设计模式,当然是设计的模式,不是代码的模式。应该是让我们有好的设计,最后代码只是设计的具体表现,让我们的代码看起来更具模块化,相互之间的耦合度更低。
实现设计和实现编码是两个过程,网上写了这么多例子,应该能看出来用来实现一个模式的编码不是一个固定的编码结构,其中可能会有这样那样的变化,但是根据具体项目的需求实现了目的,我认为就是实现了我们的设计。
引一个
我们就是要实现提供一个AbstractFactory接口来实现系列对象的创建,至于对象怎样创建,他们之间体关系是怎样实现的都不需要客户程序来关心,客户程序需要做的就是使用这个接口就得到了它需要的一系列对象。
上周末在和大家讨论的时候,被问道“最后即使是改一处还是需要修改代码啊?而且对于系列产品的创建为什么不写成一个接口?”,第二个问题比较好解答,因为像我前面说的实现不是一个固定的代码结构。第一个问题在我看了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
{
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
{
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放在相应的路径下并配合配置文件即实现了我们的扩展。