最近学习设计模式时,遇到了“三兄弟模式”,这三个家伙可把我搞晕了,通过查阅资料和个人理解,整理出了这篇文章,希望能帮到大家。
简单工厂:
简单工厂模式中,包括一个“抽象产品类”(该类可以是接口Interface,也可以是实际的类Class),所有需要的产品类都是该“抽象产品类”的子类(如果是接口的话,那么就是说所有产品类都继承了该接口)。
另外还包含一个具体的工厂类,由该工厂类生成所有的产品类的对象,其内部一般是类似于switch的结构,根据选择来创建不同类型的对象。
用小米公司生产手机做个例子:这里的“小米手机”就是“抽象产品类”,而具体的产品如“小米3、红米”等是继承了“小米手机”的子类,简单工厂类就是XiaomiFactory,工厂方法就是CreateXiaoMiPhone,参数是手机型号,根据不同型号创建不同的小米手机(使用case)。
代码结构图:
代码:
//制造小米手机类
public class MiPhone
{
public virtual void Show()
{
Console.WriteLine(" ");
}
}
//具体手机类
class Mi3 : MiPhone
{
public override void Show()
{
Console .WriteLine ("我是速度最快的小米3! ");
}
}
class HoneMi : MiPhone
{
public override void Show()
{
Console.WriteLine("我是性价比最高的红米! ");
}
}
class Mi2S : MiPhone
{
public override void Show()
{
Console.WriteLine("额...我是一直降价的小米2S - -! ");
}
}
// 简单小米工厂类
public class XiaoMiFactory
{
public static MiPhone CreateXiaoMiPhone(string Model)
{
MiPhone pho = null;
switch (Model)
{
case "Mi3":
pho = new Mi3();
break;
case "HongMi":
pho = new HoneMi();
break;
case "Mi2S":
pho = new Mi2S();
break;
}
return pho;
}
}
//客户端代码
<pre class="csharp" code_snippet_id="246967" snippet_file_name="blog_20140320_5_2344108" name="code"> static void Main(string[] args)
{
MiPhone pho;
pho = XiaoMiFactory.CreateXiaoMiPhone("Mi3");
pho.Show();
Console.WriteLine();
pho = XiaoMiFactory.CreateXiaoMiPhone("Mi2S");
pho.Show();
Console.WriteLine();
pho = XiaoMiFactory.CreateXiaoMiPhone("HongMi");
pho.Show();
Console.WriteLine();
}
显示:
缺点:很明显就是小米公司每发明一个新型号的手机都需要修改简单工厂类(增加case判断),违反了封闭修改,开放扩展原则。这可怎么解决呢?不用担心,在下面会找到答案的。
工厂方法:
它的核心是:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。具体来说,该模式把工厂类抽象出了一个接口(该接口只有创建抽象产品的工厂方法),其他具体生成对象的工厂去实现这个接口。注意工厂方法的每个具体工厂只负责返回一种产品类。
没有例子是很难理解的,同样以小米手机生产做例子:
科技在发展,时代在进步。小米公司即将推出一款性价比超越红米的霸气神鸡,名之曰“红米Note”(3月26日开放购买,想换手机的同学赶紧预约哦!)但是随着问题就来了,如果小米公司用简单工厂模式的话,那么增加一款红米Note,就需要添加一个红米Note类,还需要修改小米工厂,在Switch中增加分支,这就违反了开闭原则。那么就试试新学的工厂方法模式。
首先定义工厂抽象接口interfaceXiaoMiFactory,然后再添加具体生产手机的工厂,米3工厂,红米工厂等
代码结构图:
代码:
//小米手机类
public class MiPhone
{
public virtual void Show()
{
Console.WriteLine(" ");
}
}
//具体手机类
class Mi3 : MiPhone
{
public override void Show()
{
Console.WriteLine("我是速度最快的小米3! ");
}
}
class Mi2S : MiPhone
{
public override void Show()
{
Console.WriteLine("额...我是一直降价的小米2S - -! ");
}
}
class HoneMiNote : MiPhone
{
public override void Show()
{
Console.WriteLine("我是红米Note,性价比历史新高! ");
}
}
// 小米工厂接口
interface XiaoMiFactory
{
MiPhone CreatXiaoMiPhone();
}
// 制造小米3 的工厂
class Mi3Factory : XiaoMiFactory
{
public MiPhone CreatXiaoMiPhone()
{
return new Mi3();
}
}
// 制造 红米Note 的工厂
class HongMiNoteFactory : XiaoMiFactory
{
public MiPhone CreatXiaoMiPhone()
{
return new HoneMiNote();
}
}
// 制造小米2S 的工厂
class Mi2SFactory : XiaoMiFactory
{
public MiPhone CreatXiaoMiPhone()
{
return new Mi2S();
}
}
//客户端代码
static void Main(string[] args)
{
XiaoMiFactory factory = new HongMiNoteFactory();
MiPhone hongminote = factory.CreatXiaoMiPhone();
hongminote.Show();
Console.WriteLine();
}
抽象工厂:核心-提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。该模式和工厂方法模式很相似,也是一个抽象工厂接口和若干个具体的工厂,而不同的是抽象工厂接口定义了多个虚工厂方法,每个虚工厂方法负责制造一种产品,多个工厂方法返回多种产品,并且这些产品具有某些联系。
我们接着来举小米手机例子:上面已经说到了小米公司在生产手机的时候也会根据每个手机的型号生产出对应的充电器等配件,这就相当于两种相互联系的产品。XiaoMiFactory会定义两个虚工厂方法,一个是CreateXiaoMiPhone用来生产手机,另一个是CreateXiaoMiCharger用于生产对应型号的手机充电器(在这里假定不同型号手机使用不同的充电器)。
代码结构图:
//小米手机类
public class MiPhone
{
public virtual void Show()
{
Console.WriteLine(" ");
}
}
//小米充电器类
public class MiCharger
{
public virtual void Show1()
{
Console.WriteLine(" ");
}
}
//具体手机类
class Mi3 : MiPhone
{
public override void Show()
{
Console.WriteLine("我是速度最快的小米3! ");
}
}
class HoneMiNote : MiPhone
{
public override void Show()
{
Console.WriteLine("我是红米Note,性价比历史新高! ");
}
}
//具体充电器类
class Mi3Charger : MiCharger
{
public override void Show1()
{
Console.WriteLine("我是小米3的专属充电器 ! ");
}
}
class HoneMiNoteCharger : MiCharger
{
public override void Show1()
{
Console.WriteLine("我是红米Note的专属充电器! ");
}
}
// 小米工厂接口
interface XiaoMiFactory
{
MiPhone CreatXiaoMiPhone();
MiCharger CreatXiaoMiCharger();
}
// 制造 红米Note 的工厂
class HongMiNoteFactory : XiaoMiFactory
{
public MiPhone CreatXiaoMiPhone()
{
return new HoneMiNote();
}
public MiCharger CreatXiaoMiCharger()
{
return new HoneMiNoteCharger();
}
}
// 制造小米3 的工厂
class Mi3Factory : XiaoMiFactory
{
public MiPhone CreatXiaoMiPhone()
{
return new Mi3();
}
public MiCharger CreatXiaoMiCharger()
{
return new Mi3Charger();
}
}
客户端代码:
static void Main(string[] args)
{
XiaoMiFactory factory = new XiaoMiFactory();
MiPhone hongminote = factory.CreatXiaoMiPhone();
MiCharger hongminotecharger = factory.CreatXiaoMiCharger();
hongminote.Show();
hongminotecharger.Show1();
Console.WriteLine();
}
显示效果:
优点:使具体创建实例的过程与客户端分离,隔离了具体类的生产,使得客户并不需要知道什么被创建。当增加新手机和充电器的时候,只需要增加相应的具体工厂和具体类即可,符合开闭原则和依赖倒转原则。
缺点:增加新的产品等级结构很复杂,需要修改抽象工厂和所有的具体工厂类,对“开闭原则”的支持呈现倾斜性。如果要增加移动电源这项产品就需要增加电源基类,红米Note电源类,Mi3电源类等,还要改动工厂接口和具体工厂,这显然又不符合开闭原则。
小结:
1、简单工厂对于产品的创建,由一个工厂类来控制,如果增加新产品,那么增加新产品类的同时,还要对工厂类做相应的修改,增加case分支,这和开闭原则的违背的。(这个模式适用于一样不会增加新产品的情况)
2、工厂方法对于产品的创建则是由各具体产品工厂负责(每个产品都会建有工厂),独立进行创建的,这样在添加产品时,只需增加相应工厂和产品类即可,保证的开闭原则。
3、抽象工厂,我们可以把工厂方法理解为特殊的抽象工厂,这个产品结构属于一种类型有多个产品。而如果是几种类型的,每个类型又有多个产品,这时就需要用到抽象工厂来实现了。
天下没有完美的设计模式,每个模式都有其优缺点,我们需要做的就是在合适的场合利用合适的设计模式,这样才能发挥出模式的最大能量,设计出优美的程序。