【引用】简单工厂,工厂方法与抽象工厂模式区别与联系(汇总)
luyued 发布于 2011-04-27 15:16 浏览 N 次[转:http://m.cnblogs.com/25054/1545462.html?full=1]
设计模式作为程序员的内功心法,相信每个写过OOP代码的都不会陌生,不过有些模式之间既有区别,又有联系,我们来看看简单工厂,工厂方法与抽象工厂的区别和联系。
一、简单工厂
简单工厂模式中工厂为具体工厂,产品为抽象产品,由工厂实例创建产品实例。
二、工厂方法
工厂方法中有抽象的工厂类,一种抽象的产品类,而工厂类中仅创建此抽象产品类的实例,具体产品实例由具体的工厂类创建。
三、抽象工厂
抽象工厂创建多类产品,可将这些产品理解为一套相关的产品,由工厂在创建时一起创建,每类产品有不同的实例。实践中一般会用反射来创建工厂的实例,配合配置文件或依赖注入容器来避免创建不同产品时还需要修改客户端代码,即符合“修改封闭,扩展开放原则”,一点拙见,欢迎指正。
以下转自terryLee的博客:
概述
在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时由于需求的变化,往往存在着更多系列对象的创建工作。如何应对这种变化?如何绕过常规的对象的创建方法(new),提供一种“封装机制”来避免客户程序和这种“多系列具体对象创建工作”的紧耦合?这就是我们要说的抽象工厂模式。
意图
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
模型图
逻辑模型:
物理模型:
利用设计模式可以使我们的代码更灵活,更容易扩展,更容易维护。各种面向对象的程序设计语言都提供了基本相同的机制:比如类、继承、派生、多态等等。但是又有各自的特色,C# 中的反射机制便是一个很重要的工具,好好地利用就可以在实际中发挥很大的作用。
我们来看一个例子:
我的程序中有需要一系列的对象,比如apple,orange…, 要想利用他们,我们就必须在程序中根据用户要求,然后一个个调用 new 操作符来生成他们,这样客户程序就要知道相应的类的信息,生成的代码显然不够灵活。我们可以在代码中不利用具体的类,而只是说明我们需要什么,然后就能够得到我们想要的对象吗?
哦,我们都看设计模式,听吧,很多人都在那里鼓吹他们是如何如何的棒,我们看看怎么样利用他们来解决问题。目标明确了,那我们看看哪个能够符合我们的要求。GoF的《设计模式》都看过吧,似懂非懂的看了一些,那我们看看能够不能够“凑”上去呢?J 嗯,我们的程序考虑的是对象怎么创建的,创建型模式应该符合要求吧。然后我们浏览一下各模式的“意图”部分。呵呵,第一个好像就撞到彩了,抽象工厂,我们看看吧,“提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类”,至少“无需指定它们具体的类”符合我们的要求。来看看它的结构(上图)
我们的问题好像用不到这么复杂吧,只有orange,apple等等(应该就是product了),他们显然是一类的,都是fruit,我们只要一个生产水果的工厂就可以,左边的继承层次不要,只有一个FruitFactroy看看行不,先别管它正统不正统,实用就行J
下面的一些东西显然是我们需要的:
Public interface IFruit
{
}
public class Orange:IFruit
{
public Orange()
{
Console.WriteLine("An orange is got!");
}
}
public class Apple:IFruit
{
public Apple()
{
Console.WriteLine("An apple is got!");
}
}
我们的FruitFactory应该是怎么样呢?上面的结构图中它给的是CreateProductA,那好,我就MakeOrange,还有一个CreateProductB,俺MakeOrange还不行??
public class FruitFactory
{
public Orange MakeOrange()
{
return new Orange();
}
public Apple MakeApple()
{
return new Apple();
}
}
怎么使用这个工厂呢?我们来写下面的代码:
string FruitName = Console.ReadLine();
IFruit MyFruit = null;
FruitFactory MyFruitFactory = new FruitFactory();
switch (FruitName)
{
case "Orange":
MyFruit = MyFruitFactory.MakeOrange();
break;
case "Apple":
MyFruit = MyFruitFactory.MakeApple();
break;
default:
break;
}
编译运行,然后在控制台输入想要的东西,呵呵,成功了。沉浸在幸福中的你得意忘形了吧。
不过等等,它好像还不完美,我如果想要pear,我既要在客户代码中的switch中加入判断,又要在工厂方法中加入MakePear方法,好像不怎么优雅。更好一点,在工厂中只提供一个方法,MakeFruit,然后传递进一个参数Name,代表我们想要的水果的名称,这样的话,似乎我们的客户代码中的那个switch就可以不要了,相反,在FruitFactory中好像需要一个,还等什么呢?实现吧。
FruitFactory:
public class FruitFactory
{
public IFruit MakeFruit(string Name)
{
switch (Name)
{
case "Orange":
return new Orange();
case "Apple":
return new Apple();
default:
return null;
}
}
}
客户代码:
string FruitName = Console.ReadLine();
IFruit MyFruit;
FruitFactory MyFruitFactory = new FruitFactory();
MyFruit = MyFruitFactory.MakeFruit(FruitName);
这样看起来好多了,至少我客户代码中不要再写那么一长串的判断代码了。
阿Q精神又在起作用,我们又沉浸在成功的喜悦中了。 嗯,代码好像可以,应该没有什么改进了。但是好像又有另外一个声音在说:
“除了一点……”
“嗯? 等等,什么?”
“FruitFactory也有switch啊,看起来也ugly啊!”
“哼,肯定是看《重构》或者是《TDD》了,怎么要求那么苛刻!反正闲着也是闲着,看看可以改不?”
既然不要条件判断,传入的只有水果的名称,假如Name = “Apple”,要生成一个Apple的对象,我需要new Apple(),如果我能够这样多好: new MakeItToClass(Name),把字符串转换成一个类。C#中虽然没有上述语法,但是提供了相应的机制,那就是反射。其中一个重要的类就是System.Type类,它对于反射起着核心的作用。我们可以使用 Type 对象的方法、字段、属性和嵌套类来查找有关该类型的所有信息。
另外一个重要的类就是System.Activator,它包含特定的方法,用以在本地或从远程创建对象类型,或获取对现有远程对象的引用。
我们可以先利用Type类获取Name指定的类名的类的Type信息,然后可以根据这个信息利用Activator创建对象。还等什么呢?
public class FruitFactory
{
public IFruit MakeFruit(string Name)
{
IFruit MyFruit = null;
try
{
Type type = Type.GetType(Name,true);
MyFruit = (IFruit)Activator.CreateInstance(type);
}
catch (TypeLoadException e)
Console.WriteLine("I dont know this kind of fruit,exception caught - {0}" ,e.Message);
return MyFruit;
}
}
经过这样的处理以后,增加新的水果的时候,我们不需要修改客户代码了,同时工厂的代码也不需要修改了!
运用样例:
AbstractMessageModel:
using System;
using System.Collections.Generic;
using System.Text;
namespace Pattern.AbstractFactory
{
/**////
/// 抽象Message实体类(AbstractProduct)
///
public abstract class AbstractMessageModel
{
/**////
/// 构造函数
///
public AbstractMessageModel()
{
}
/**////
/// 构造函数
///
/// Message发布时间
public AbstractMessageModel(string msg, DateTime pt)
{
this._message = msg;
this._publishTime = pt;
}
private string _message;
/**////
/// Message内容
///
public string Message
{
get { return _message; }
set { _message = value; }
}
private DateTime _publishTime;
/**////
/// Message发布时间
///
public DateTime PublishTime
{
get { return _publishTime; }
set { _publishTime = value; }
}
/**////
/// UserId
///
public abstract string UserId
{
get;
set;
}
}
}
SqlMessageModel:
using System;
using System.Collections.Generic;
using System.Text;
namespace Pattern.AbstractFactory
{
/**////
/// SqlMessage实体类(Product)
///
public class SqlMessageModel : AbstractMessageModel
{
/**////
/// 构造函数
///
public SqlMessageModel()
: base()
{
}
/**////
/// 构造函数
///
/// UserId
/// Message发布时间
public SqlMessageModel(string userId, string msg, DateTime pt)
: base(msg, pt)
{
this._userId = userId;
}
private string _userId;
/**////
/// Message内容
///
public override string UserId
{
get { return _userId; }
set { _userId = value; }
}
}
}
XmlMessageModel:
using System;
using System.Collections.Generic;
using System.Text;
namespace Pattern.AbstractFactory
{
/**////
/// XmlMessage实体类(Product)
///
public class XmlMessageModel : AbstractMessageModel
{
/**////
/// 构造函数
///
public XmlMessageModel()
: base()
{
}
/**////
/// 构造函数
///
/// UserId
/// Message发布时间
public XmlMessageModel(string userId, string msg, DateTime pt)
: base (msg, pt)
{
this._userId = userId;
}
private string _userId;
/**////
/// Message内容
///
public override string UserId
{
// 解密算法后的值
get { return _userId; }
// 加密算法后的值
set { _userId = value; }
}
}
}
AbstractMessage:
using System;
using System.Collections.Generic;
using System.Text;
namespace Pattern.AbstractFactory
{
/**////
/// 操作Message抽象类(AbstractProduct)
///
public abstract class AbstractMessage
{
/**////
/// 插入Message
///
/// AbstractMessageModel
///
public abstract string Insert(AbstractMessageModel amm);
}
}
SqlMessage:
using System;
using System.Collections.Generic;
using System.Text;
namespace Pattern.AbstractFactory
{
/**////
///
public class SqlMessage : AbstractMessage
{
/**////
/// 插入Message
///
/// AbstractMessageModel
///
public override string Insert(AbstractMessageModel amm)
{
return "Sql方式插入Message。帐号:" + amm.UserId
+ ";内容:" + amm.Message
+ ";时间:" + amm.PublishTime.ToString();
}
}
}
XmlMessage
using System;
using System.Collections.Generic;
using System.Text;
namespace Pattern.AbstractFactory
{
/**////
///
public class XmlMessage : AbstractMessage
{
/**////
/// 插入Message
///
/// AbstractMessageModel
///
public override string Insert(AbstractMessageModel amm)
{
return "Xml方式插入Message。帐号
- 06-12· QQ留言摘抄,(第一季)
- 05-23· 办公家具维修13146869485办公
- 05-23· 北京办公用品北京办公家
- 05-23· 陶瓷价格指数启动
- 05-23· 卫浴机械设备-浴缸机械设
- 05-23· [转载]老夫子选股法
- 05-21· 小面积的浴室佳选:美国绅
- 05-21· 带按摩浴缸 美国绅士德
- 05-21· 随心所“浴” 带按摩浴缸
- 05-21· 2千元的多功能淋浴房 艾得
- 05-21· 绅士德fj-317蒸汽房评测(图
- 05-21· 加枫淋浴房SV11评测(图)-加
- 05-21· 哈尔滨唯尚摄影个性男写
- 05-21· 我和男友起死回生的爱情
- 05-21· 公司介绍--唯尚北京办事处
- 05-21· 唯尚咖啡里的爱情时光
- 05-21· 《唯尚圣经》:最美紫罗兰
- 05-21· 全家福-《尖刀门市集训营
- 05-21· 唯尚眼镜公司
- 05-21· 不同身形新娘如何选择婚