`
iwebcode
  • 浏览: 2008519 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

简单工厂,工厂方法,抽象工厂之比较

 
阅读更多

创建模式的目的就是为了解决使用和生产责任分离,当然能使用这种模式的前提就是用户并不关心"产品"的创建逻辑和过程,用户只需要对创建的结果进行使用.在这种情况下,将使用和创建分离就增加了程序的灵活性,因为"产品"的构建对用户来说是透明的,如果需要对创建过程增加功能(比如增加创建权限检查),不会影响到用户的使用.

模式的应用有两个基本的目的,一是复用,二是适应变化.而且这两个目的在很大程度上也是统一 的.工厂类模式将使用和创建责任分离,其实就是为了适应"创建"的变化.当然这种"适应变化"的代价就是需要增加工厂类,增加了系统的复杂度和开销.因此选择模式的一个重要的工作就是要权衡利弊,其实在创建模式中就有一个隐形假设:工厂角色的变化相对固定,工厂类本身的创建非常简单.这个假设很重要,因为如果工厂本身的创建和可变性都很大的话,采用这种模式就得不偿失了.

简单工厂模式的原理其实很简单,就是将"产品"的创建工作委托给工厂类的静态方法来完成,有抽象产品的情况下,用户只需要用一个参数调用来获得"产品",而不需要知道具体的产品的细节,比如,抽象产品为水果,用户如果需要获取产品"苹果",则只要将"苹果"作为参数来调用水果工厂的创建水果的方法,而不需要知道苹果类本身的细节.这是简单工厂模式的好处.跟工厂方法相比,简单工厂模式逻辑简单,额外开销小(增加产品,不需要增加工厂类,因为是静态方法,工厂类本身也不需要创建等).

工厂方法模式的原理也是将"产品"的创建委托给工厂类进行,但由于工厂类的创建方法不是静态的,因此可以利用继承的好处,将具体的创建工作"延时"到子类进行.这种方式在设计和思考上是有非常大的好处的:将设计分层,每一层都只需要关心同一层面上的事情.工厂方法的做法是每个具体产品都用一个具体的工厂来进行创建.这样做的好处是符合面向对象编程的开放封闭原则,增加新的产品,只需要增加新的工厂类即可(对扩展开放),对任何产品的增加或修改,不会影响其它工厂类和产品类(对修改封闭),但缺点也是非常明显的,就是产品多的时候,系统中的类会很多.(成倍增加).跟简单工厂模式相比,一是系统不简洁,二是增加了工厂类的创建,三是用户的选择产品逻辑变成了对工厂类的选择,降低了选择的直观性.

抽象工厂方法可以看作是工厂方法的更一般的表达,抽象工厂针对的是产品族的概念(如果只有一种产品,就是工厂模式),如果按照抽象工厂的严格意义上来讲,应用场景会比较少(多种数据库支持,多种语言版本的情况可以用).能使用抽象工厂的应用场景一般可以表达为矩阵模型,同一行的是不同环境中的同一个产品的实现,同一列的产品都处于同一个应用环境下,系统每次只会用到一种环境的产品.典型的应用是Windows和Linux下的界面控件.如果只一族产品,则抽象工厂就可以退化成简单工厂来实现.

在实际使用中,简单工厂模式和工厂方法模式用得比较多,而抽象工厂方法用得比较少.当然,抽象工厂在类似于数据库连接方面应用还是比较好的,比如系统如果需要支撑多种数据库系统,就可以采用抽象工厂来进行构建.

===============================

其实类的创建现在有了一些新的变化,例如,将创建依赖放在配置文件,采用反射技术来构造实例,这种方法的好处是一时可以减少工厂类,极端的情况下一个工厂方法就可以了,同时工厂类与产品类也脱耦。现在有很多框架都采用这种方式(如Nhibernate等),就是所谓的依赖注入,如下所示:

public interface IPersonDao
{
int SaveData();
}

public class PersonDao : IPersonDao
{
#region IPersonDao 成员

public int SaveData()
{
return 100;
}

public PersonDao()
{
}
#endregion
}
public class ObjectFactory
{
private static Dictionary<string, string> _objects = null;
static ObjectFactory()
{
string theFile = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "MyObjects.xml";
XElement root = XElement.Load(theFile);
var objs = from obj in root.Elements("object")
select obj;
_objects = objs.ToDictionary(k => k.Attribute("id").Value, v => v.Attribute("value").Value);
}
public static TRetObj GetObject<TRetObj>(string objectcode)
{
string theClassType = _objects[objectcode];

Type theType = Type.GetType(theClassType, false, true);
return (TRetObj)Activator.CreateInstance(theType);
}
}

MyObjects.xml

<?xml version="1.0" encoding="utf-8" ?>
<objects>
<object id="PersonDao" value="SpringNetStudy.PersonDao,SpringNetStudy"/>
</objects>

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics