w.rong

人生的价值,并不是用时间,而是用深度去衡量的。
   :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

对抽象工厂的改造(原创)

Posted on 2007-02-22 07:12 rongwei 阅读(6153) 评论(18)  编辑 收藏 所属分类: 设计模式
关键词:
抽象工厂
适合读者:
中级
摘要:
通过对抽象工厂的改造使变得简单和更具有扩展性。
内容:
首先我来分析一下抽象工厂模式:


我们为什么要这么设计呢?是因为我们有这样的要求:

老板:我要做一种产品。
程序员:我们没有考虑,直接做了一个产品类(ProductA1)和 产品线ProductFactory1。
老板:我还要再做另一种产品。
程序员:我们没有考虑,又做了一个产品类(ProductA2)。
老板:我还要再做另一种产品。
程序员:我们没有考虑,又做了一个产品类(ProductB1)。
老板:我还要再做另一种产品。
程序员:愤怒,又做了一个产品类(ProductB2)。
老板:使用中。。。
程序员:怕了他了,所以做了一个扩展, 抽象出来 AbstractProductA AbstractProductB。
老板:经过使用我们发现要新增我们的产品线来提高效率
程序员:没考虑,怎加了产品线ProductFactory2。
老板:经过我们的考虑两条产品线还是不能满足要求。
程序员:怕了他了,所以做了一个扩展 抽象出来AbstractFactory。

到现在我们看似完成了,其实是一团糟,让我们看看都做了什么,当我们产品类需要增加一个方法时,需要改写产品类的同时
要怎加产品线方法和产品线接口,更遭的是要增加产品线。依赖关系依然没有太大改善。

现在我们解决它:



实现:下面是一个接口的例子(我懒得改成抽象类,道理是一样的)。
 1 public interface IFactory
 2 {
 3     object Create(string className);
 4 }
 5 
 6 public ProductFactory : IFactory
 7 {
 8     object CreateProduct(string className)
 9     {
10         string path = "程序集";
11         return Assembly.Load(path).CreateInstance(path + "." + className);
12     }
13 }
14 
15 // 注意 dll 可以根据需要做成一个或多个
16 public interface IProductA {}
17 
18 public ProductA1 : IProductA {}
19 
20 public ProductA2 : IProductA {}
21 
22 public interface IProductB {}
23 
24 public ProductB1 : IProductB {}
25 
26 public ProductB2 : IProductB {}    
27 
28 
29 main()
30 {
31     IFactory factory = new ProductFactory();
32     IProductA productA = (IProductA)factory.CreateProduct("类名");
33 }

能够应用这个的地方有很多,包括我举的这个例子,还可以重构一下 16 - 26 行的代码。

最后,这是我做项目中的一点小经验,夜里写的,有说的不对或没有讲清的或完全不对的请批评指教。谢谢。

Feedback

#1楼    回复  引用  查看    

2007-02-22 09:35 by JesseZhao      
不错,看起来很爽

#2楼    回复  引用  查看    

2007-02-22 09:36 by JesseZhao      
作者的排版和格式都很正规,佩服一个

#3楼    回复  引用    

2007-02-22 09:43 by 剑在上海^^ [未注册用户]
LZ用反射实现...感觉怪怪的

#4楼 [楼主]   回复  引用  查看    

2007-02-22 11:36 by 荣伟      
谢谢你们,
抽象出来的东西本意是不变的,只要它变了,就等于我们什么也没有做。

题外话:
我最早还想过语言什么时候能出一个向上定义的关键字,即基类可以感知派生类在做什么,并不只是控制和限制派生类。

#5楼    回复  引用  查看    

2007-02-22 14:34 by T.t.T!Ck.      
petshop的数据层也是这样映射的 ^_^

#6楼 [楼主]   回复  引用  查看    

2007-02-22 14:40 by 荣伟      
@T.t.T!Ck. 你好
petshop的返回值是具体的类,也就是说它不得不做很多方法,在这里的返回值是object,区别很大。

#7楼 [楼主]   回复  引用  查看    

2007-02-22 14:42 by 荣伟      
6-13行名字写错了,不好意思。
应为接口的实现 :
6 public ProductFactory : IFactory
7 {
8 object Create(string className)
9 {
10 string path = "程序集";
11 return Assembly.Load(path).CreateInstance(path + "." + className);
12 }
13 }

#8楼    回复  引用  查看    

2007-02-22 17:31 by YAO.NET℡      
32行也同样要改:
CreateProduct->Create

建议在原文中把所有错误都修正.

#9楼    回复  引用  查看    

2007-02-22 21:30 by yunhuasheng      
很好!!

#10楼    回复  引用  查看    

2007-02-22 23:57 by 若寒      
好!收了.

#11楼    回复  引用    

2007-02-23 10:54 by zhang [未注册用户]
好.写的好

#12楼    回复  引用    

2007-02-23 12:07 by hkthk [未注册用户]

#13楼    回复  引用  查看    

2007-02-24 00:14 by Leepy      
@YAO.NET℡
32行应该没有问题吧!

#14楼    回复  引用  查看    

2007-02-24 00:15 by Leepy      
不错,分析得好!

#15楼    回复  引用  查看    

2007-02-24 05:22 by Ying-Shen      
我的理解是抽象工厂模式的通过建立不同的工厂类来隐藏是创建不同产品系列的时候的不同的实现。所以抽象工厂模式的前提是不同系列产品的构建方式是不同的。

后面的改造方法则似乎在说ProductFactory1和ProductFactory2所隐藏的创建逻辑实际上是相同的。这样ProductFactory类其实已经退化为一个工厂方法。如果是这个意思,那么这里继承IFactory也不是必需的吧。

还有就是看到现在的示例代码中已经把不同产品线产品的创建逻辑简化到反射创建对象这种语言特性上,我猜想这里作者是不是在调整的时候把原来一部分对象创建的那部分有差异的逻辑移到了产品类的代码之中了,如果是这样可能要考虑产品类的职责定义修改以及封装可能被破坏的问题。


#16楼    回复  引用    

2007-02-24 08:41 by Bomb.Zhang [未注册用户]
完全同意 Ying-Shen 的观点。
楼主的这个改造后的抽象工厂模式事实上已经不是真正意义上的抽象工厂模式了,而可以被认为是参数化的工厂方法模式,IFactory已经没有必要存在了。
另外,楼主在对 T.t.T!ck 的回复中说“在这里的返回值是object,区别很大”,个人认为这个解释是不合理的,抽象工厂方法解决的是创建不同级别的分系列的产品的创建问题,如果返回值都是object,则失去了原有的意义了。
但在.Net体系中,楼主还是可以使用这种方法来创建对象的。
关于抽象工厂模式,请参考吕震宇的文章 http://www.cnblogs.com/zhenyulu/articles/36885.html,另外建议参考他的设计模式系列 http://www.cnblogs.com/zhenyulu/category/6930.html?Show=All

#17楼 [楼主]   回复  引用  查看    

2007-02-26 09:28 by 荣伟      
@Ying-Shen,您好
是的,我只是拿了抽象工厂做个例子来改造一下,从而达到说明问题,以后有机会我还会把这个问题从各个方面全部叙述一下(性能 封装性等方面)

#18楼    回复  引用    

2007-02-27 11:26 by sharmy [未注册用户]
ding csh

标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2007-02-22 07:17 编辑过
 
另存  打印