设计模式——工厂模式
工厂模式在我们的项目当中会被频繁使用,这主要是因为他解决了关键字new所引发的类与类之间的依赖。或者说通过工厂能够很好的将类与类解耦。
假设我们是一家手机制造商,好很多品牌的手机都在我们这里下单,进行批量生产制造。其中有Nokia、HTC、Samsung。我要获得一部三星手机。这个程序可以如何写呢?
来看第一个程序。
namespace DesignPattern.Factory
{
public class Phone
{
private string _brand;
public string Brand
{
get { return _brand; }
set { _brand = value; }
}
public override string ToString()
{
return string.Format("品牌:{0}",_brand);
}
}
}
namespace DesignPattern.Factory
{
class Program
{
static void Main(string[] args)
{
Phone myPhone = new Phone();
myPhone.Brand = "Samsung";
Console.WriteLine(myPhone.ToString());
}
}
}
好吧,这里只有两个角色,一个“电话”,一个“客户”。看起来很别扭。原因就在看起来像客户制造的手机,并且是客户给品牌命名的。并且,如果我动了Phone类的一些东西,那么客户的手机就必须重新制造。好吧,那么咱们重新搞一搞他,引入一个Phone工厂。
首先我们需要把Phone抽象化,使Nokia、HTC、Samsung分别继承它。
public abstract class Phone
{
private string _brand;
protected void SetBrand(string brand)
{
this._brand = brand;
}
public override string ToString()
{
return string.Format("品牌:{0}",_brand);
}
}
public class NokiaPhone:Phone
{
public NokiaPhone()
{
this.SetBrand("Nokia");
}
}
public class HTCPhone:Phone
{
public HTCPhone()
{
this.SetBrand("HTC");
}
}
public class SamsungPhone:Phone
{
public SamsungPhone()
{
this.SetBrand("Samsung");
}
}
我们需要一个工厂,通过一个传入进来的字符串(或者是枚举,推荐枚举)的不同,让其产生不同的Phone对象。
public class PhoneFactory
{
private BrandEnum _brandEnum;
public PhoneFactory(BrandEnum brandEnum)
{
this._brandEnum = brandEnum;
}
public Phone CreatePhone()
{
Phone phone = null;
switch (this._brandEnum)
{
case BrandEnum.Nokia:
phone = new NokiaPhone(); break;
case BrandEnum.HTC:
phone = new HTCPhone(); break;
case BrandEnum.Samsung:
phone = new SamsungPhone(); break;
default:
break;
}
return phone;
}
}
现在在开看看调用代码。
static void Main(string[] args)
{
Phone myPhone = new PhoneFactory(BrandEnum.Samsung).CreatePhone();
Console.WriteLine(myPhone.ToString()+
" 类型:"+myPhone.GetType());
Console.ReadKey();
}
好像看起来好多了,让我们来看一下依赖项。
Program只知道我要一个电话,一个三星电话,把这个具体的实例工作交给了PhoneFactory。PhoneFactory根据Programs所提出的要求实例化不同品牌的电话产品,并交给Program。这就是简单工厂,PhoneFactory可以将产品和客户进行解耦。
现在有个问题。PhoneFactory和具体的品牌手机是耦合的,而且相当严重。当我新添加一个手机品牌的时候就必须要修改PhoneFactory。在OO思想中应该尽量避免修改。我们可以将工厂类抽象出去,在下面建立许多小工厂,并且将制造电话的步骤放在小工厂中进行,这样添加一个品牌手机的时候就不用修改PhoneFactory了,而是添加一个SomePhone和一个SomeFactory就可以了。
先来改造一下PhoneFactory,实例化的过程放在小工厂中(因为具体到了小工厂中处理实例化对象,也就是已经知道了产品是什么,所以枚举可以不用判断了,也就是在工厂当中将switch/case剔除掉了),PhoneFactory声明一个抽象方法,让小工厂去实现各自的品牌。
public abstract class PhoneFactory
{
public PhoneFactory()
{
}
public abstract Phone CreatePhone();
}
诺基亚小工厂,其他依次类推。
public class NokiaFactory:PhoneFactory
{
public override Phone CreatePhone()
{
return new NokiaPhone();
}
}
。。。。。。
再来得到一部三星手机。
class Program
{
static void Main(string[] args)
{
Phone myPhone = new SamsungFactory().CreatePhone();
Console.WriteLine(myPhone.ToString()+
" 类型:"+myPhone.GetType());
Console.ReadKey();
}
}
我们再来看一下UML中的依赖关系。
可以看到小工厂以及,品牌电话具有依赖,而其他的都被解耦了,而添加一个品牌电话,则必须伴随一个小工厂,他们是成对出现的,他们的修改不影响其他类。这就是工厂模式。