您的位置:首页 > 其它

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

2006-08-02 17:33 399 查看
抽象工厂模式,花了一些时间来学习它,它的意图就是“提供一个接口,让该接口负责创建一系列相关或者相互依赖的对象,无需指定它们具体的类”,对于已有系列对象的创建时,根据需要替换起来很方便。但是对于新增系列对象的替换则还是需要像原来一样,最起码要新增加这个我们需要的新类,但是这种良好的结构为我们提供了很方便的扩展方法。个人感觉它的缺点就是不能创建有着不同个数对象的系列,不过应该是可以通过工厂方法来解决的,这个留做以后解决的问题。

看到很多相关文章最后都是付诸于代码的实现,自己感觉TerryLee的就比较好,设计模式设计模式,当然是设计的模式,不是代码的模式。应该是让我们有好的设计,最后代码只是设计的具体表现,让我们的代码看起来更具模块化,相互之间的耦合度更低。

实现设计和实现编码是两个过程,网上写了这么多例子,应该能看出来用来实现一个模式的编码不是一个固定的编码结构,其中可能会有这样那样的变化,但是根据具体项目的需求实现了目的,我认为就是实现了我们的设计。

引一个吕震宇老师文章里很能说明问题的图:



我们就是要实现提供一个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放在相应的路径下并配合配置文件即实现了我们的扩展。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: