1. public class SteamedBread
{
public SteamedBread() // 构造方法
{ }
private double price=0.5;
public double Price
{
get { return price; }
set { price = value; }
}
}
OK,产品对象建立好了,下面就是创建工厂(Factory)对象了。
public class Factory
{
public static SteamedBread CreateInstance() // 创建一个馒头(SteamedBread)对象
{
return new SteamedBread();
}
}
此时,客户端可以这样来调用:
public class Client
{
public static void Main(string[] args)
{
//通过工厂创建一个产品的实例
SteamedBread sb = Factory.CreateInstance();
Console.WriteLine("馒头{0}元一个!", sb.Price);
}
}
如上就完成了一个简单工厂模式的简单实现,一个产品和一个工厂,工厂负责创建这个产品。但是者种实现有一定的缺陷,为每一种产品创建一个静态方法来完成产品对象的创建,如果有多个产品则需要定义多个静态方法分别返回不同的对象,用设计原则来说的话这样的实现不符合依赖倒置原则(DIP)。如果系统里只有一个单独的产品对象,那么采用这种实现是完全可以的。
2、带抽象产品(AbstractProduct)角色的简单工厂模式实现
从上面分析中得知,这种实现得为每一种产品创建一个静态方法来完成产品对象的创建。虽然带有简单工厂的性质,但是又好象不能够完全体现出简单工厂模式的意图。简单工厂的意图是:根据提供给他的数据,返回几个可能类中的一个类的实例。根据意图出发进行分析,要实现完全满足简单工厂模式意图的程序,也就得根据提供给工厂的数据,让工厂根据这个数据来进行判断,然后返回相应的对象。OK,看看是下面这样的吗
示意性代码如下:
/// <summary>
/// 食品接口----扮演抽象产品角色
/// </summary>
public interface IFood
{
/// <summary>
/// 每种食品都有销售价格,这里应该作为共性提升到父类或是接口来
/// 由于我们只需要得到价格,所以这里就只提供get属性访问器
/// </summary>
double price{get;}
}
------------------------------------------------------------------------------------
/// <summary>
/// 馒头
/// </summary>
public class SteamedBread:IFood
{
/// <summary>
/// 构造方法
/// </summary>
public SteamedBread()
{ }
public double price
{
get
{
return 0.5;
}
}
}
------------------------------------------------------------------------------------
/// <summary>
/// 包子
/// </summary>
public class SteamedStuffed:IFood
{
public SteamedStuffed()
{ }
/// <summary>
/// 销售价格
/// </summary>
public double price
{
get
{
return 0.6; //0.6元一个
}
}
}
------------------------------------------------------------------------------------
/// <summary>
/// 工厂角色
/// </summary>
public class Factory
{
/// <summary>
/// 创建一个馒头(SteamedBread)对象
/// </summary>
/// <returns></returns>
public static IFood CreateInstance(string key)
{
if (key == "馒头")
{
return new SteamedBread();
}
else
{
return new SteamedStuffed();
}
}
}
------------------------------------------------------------------------------------
public class Client
{
public static void Main(string[] args)
{
//通过工厂创建一个产品的实例
IFood food = Factory.CreateInstance("馒头");
Console.WriteLine("馒头{0}元一个!", food.price);
food = Factory.CreateInstance("包子");
Console.WriteLine("包子{0}元一个!", food.price);
}
}
此时的设计就已经完全符合简单工厂模式的意图了。顾客(Client)对早餐店营业员(Factory)说,我要“馒头”,于是营业员便根据顾客所提供的数据(馒头),去众多食品中找,找到了然后就拿给顾客。
3、模式的演变实现
有些情况下Simple Factory可以由抽象产品角色扮演,一个抽象产品类同时是子类的工厂。也就是说,抽象产品角色扮演两种角色和职责,出了基本的定义还还兼任工厂角色的职责,负责产品的创建工作。这里我们在上面的例子基础上适当修改一下OK了,新建立一个抽象类(Evolution):
/// <summary>
/// 兼任抽象产品角色和工厂角色两种角色
/// </summary>
public abstract class Evolution
{
/// <summary>
/// 共性字段
/// </summary>
private double price;
public double Price
{
get { return price; }
set { price = value; }
}
public static Evolution CreateInstance(string key)
{
if (key == "馒头")
{
return new SteamedBread();
}
else
{
return new SteamedStuffed();
}
}
}
那现在,具体的产品对象的设计也应该修改了,把原来实现于IFood接口改为继承此抽象类,如下:
public class SteamedBread : Evolution
{
public SteamedBread()
{
this.Price = 0.5; //在构造方法里初始话属性的值
}
}
public class SteamedStuffed : Evolution
{
public SteamedStuffed()
{
this.Price = 0.6;
}
}
通过上面的演化,此时客户端的调用如下:
public class Client
{
public static void Main(string[] args)
{
Evolution el = Evolution.CreateInstance("包子");
Console.WriteLine("包子{0}元一个!", el.Price);
}
}
在实际的开发中,这种演化是很适用的,可以说是一种编程技巧吧。
4、模式的其他演变
如果系统中只有唯一的一个具体产品对象,那么可以省略抽象产品角色。这一种其实也就是本钱前面的第一种模式实现。
如果抽象产品角色省略,那么工厂角色就可以与具体产品角色合并。也就是说一个产品类就是自身的工厂。这样把原有三个独立的角色:抽象产品角色、具体产品角色和工厂角色合并为一个,这个类自己负责创建自己的实例。
注:以上演变可以从上面的程序代码中直接修改而来,这里我就不贴代码了。
六、模式优缺点
工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅"消费"产品。简单工厂模式通过这种做法实现了对责任的分割。
当产品有复杂的多层等级结构时,工厂类只有自己,以不变应万变,就是模式的缺点。因为工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,有可能造成工厂逻辑过于复杂,违背了"开放--封闭"原则(OCP).另外,简单工厂模式通常使用静态工厂方法,这使得无法由子类继承,造成工厂角色无法形成基于继承的等级结构。
七、相关模式
工厂方法模式:每个产品由一个专门的工厂来负责创建。是一种只有唯一一个产品的实现,带有简单工厂的性质。
抽象工厂模式:大致和工厂方法相同。
单例模式:单例的实现和上面模式演变中的最后一种很相似,只要把构造器私有便OK。