跟我一起学23种经典设计模式——工厂方法和抽象工厂
在继上次单例模式后,有些朋友建议我写点文字还是比较好,于是我吸取教训,哼!决定以后都只贴代码了......哈哈,跟大家开个玩笑。好了,废话不多说,直接开启我们今天的设计模式吧!
在进入正题前,我先跟大家说一个OO设计中非常非常重要的原则:开放关闭原则。“开放关闭”是什么意思呢?今天笔者跟大家分享一下个人的见解,开放的是扩展,关闭的是修改,在具体一点就是,你一个项目已经做好了,但是一个新需求出现了,你要原封不动原有的代码,而是往项目里面添加代码比如添加一个类从而实现了新需求,那么这就符合了“开放封闭原则”,这是设计模式的初衷!那么接下来就转入正题吧。
有必要跟朋友们提一下简单工厂,想到简单工厂大家脑子了就应该浮现出各个静态方法,每个静态方法传入一个参数,内部就开始if...else...或switch case起来了,那么如果有一天我行增加新产品呢,那就没办法不得不修改里面的代码了加个elseif或者case,那么这就破坏了刚才所说的“开放关闭原则”,这样额系统是死的没有弹性,不能应对新的情况。好了,“新的情况“也就是变化点出现了,OO告诉我们有变化就要封装即”封装变化“,那怎么解决呢?大家鼓掌,欢迎我们的”工厂方法“隆重登场!
首先我们先创建几种商品吧:
/// <summary>
/// 定义抽象类,以派生出具体的实体类
/// </summary>
public abstract class Bed
{
public abstract string Name { get; }
}
/// <summary>
/// 派生出两个具体的闯类:美得梦,席梦思
/// </summary>
public class MeiDeMeng : Bed
{
public override string Name
{
get{return "美得梦";}
}
}
public class XiMengSi : Bed
{
public override string Name
{
get { return "席梦思"; }
}
}
/// <summary>
/// 抽象出一个灯抽象类,并派生出灯泡,闪光灯
/// </summary>
public abstract class Light
{
public abstract string Name { get; }
}
public class Lampbulb : Light
{
public override string Name
{
get { return "灯泡"; }
}
}
public class Flashlamp : Light
{
public override string Name
{
get { return "闪光灯"; }
}
}
/// <summary>
/// 抽象出一个电视抽象类,并派生出太差了(TCL),长虹
/// </summary>
public abstract class TV
{
public abstract string Name { get; }
}
public class TCL : TV
{
public override string Name
{
get { return "TCL电视机"; }
}
}
public class ChangHong : TV
{
public override string Name
{
get { return "长虹电视机"; }
}
}
至此,我们产品都已创建好了,包括三个类别:床,灯,电视,床有美得梦和席梦思,灯有灯泡和闪光灯,以及电视有TCL和长虹电视机。那接下来我们就先实现工厂方法模式,然后在实现抽象工厂模式。
/// 工厂方法模式实现
/// </summary>
public interface IBedFactoryMethod//抽象出一个接口或抽象类,以便各个具体工厂实现
{
Bed CreateBed();
}
public class MyCompanyForBedFactoryMethod : IBedFactoryMethod
{
public Bed CreateBed()
{
return new MeiDeMeng();
}
}
public class YourCompanyForBedFactoryMethod : IBedFactoryMethod
{
public Bed CreateBed()
{
return new XiMengSi();
}
}
public interface ILightFactoryMethod
{
Light CreateLight();
}
public class MyCompanyForLightFactoryMethod : ILightFactoryMethod
{
public Light CreateLight()
{
return new Lampbulb();
}
}
public class YourCompanyForLightFactoryMethod : ILightFactoryMethod
{
public Light CreateLight()
{
return new Flashlamp();
}
}
那TV的例子就不再举例了。从这里看出,工厂方法模式首先是抽象出一个工厂的接口或者抽象类也可以,那工厂方法模式很明显符合开放关闭原则,需要什么样的具体工厂尽管添加这样的一个工厂就可以了而不用修改代码,这不就是开放扩展关闭修改的核心吗,好了,但有一个特点相信大家都看见了,就是一个具体的共产类只能生产出一种商品,比如:我要美得梦,那就要创建一个专门只生产美得梦的工厂类MyCompanyForBedFactoryMethod,看清楚哦,这个工厂类只生产美得梦哦,不能生产席梦思更别说电视和灯了,那我要席梦思,那就要创建一个专门只生产席梦思的工厂类YourCompanyForLightFactoryMethod,一样的也只能生产席梦思,不能生美得梦思更别说电视和灯了。那有的朋友说你干脆在一个工厂类里面既生产美得梦又生产席梦思不就得了,在接口或抽象里加个方法
public interface IBedFactory
{
Bed CreateMeiDeMengBed();
Bed CreateXiMengSi();
}
不就得了,何必整得这么麻烦,关键就在这里,因为工厂方法模式就是要创建出一个个非常严格的专卖店,只卖一种产品的专卖店,再说在一个工厂里面你生产美得梦又生产席梦思,这不是侵权了吗,这可是赔大钱的事啊!所以这还得根据特定的项目背景来设计。
接着,就有人问了,在工厂方法模式中每个工厂类为什么不能同时生产床,灯,电视呢,你有忘记了“工厂方法模式就是要创建出一个个非常严格的专卖店,只卖一种产品的专卖店”,那怎么办呢?接下来就是抽象工厂模式闪亮登场了,好的,我们先亮代码吧。
/// <summary>
/// 抽象出一个工厂接口或抽象类,大家看到了这里这里与工厂方法的区别了,在这个抽象接口或抽象类里有可以生产床的方法,也有生产灯的方法,也有生产电视的方法
/// </summary>
public interface IAbstracFactory
{ Bed CreateBed();
Light CreateLight();
TV CreateTV();
}
public class MyCompanyForBedLightTV : IAbstracFactory
{
public Bed CreateBed() { return new XiMengSi(); }
public Light CreateLight() { return new Lampbulb(); }
public TV CreateTV() { return new TCL(); }
}
public class YourCompanyForBedLightTV : IAbstracFactory
{
public Bed CreateBed() { return new MeiDeMeng(); }
public Light CreateLight() { return new Flashlamp(); }
public TV CreateTV() { return new ChangHong(); }
}
在这里相信大家都看出区别来了,在以前工厂方法中如果我要灯,那么我要创建出一个工厂专门只生产灯的工厂而且还只能生产一种灯不能既生产灯泡又生产闪光灯,当然这不能算是缺点,因为设计模式都是结合实际背景的,所以只能说是应用场合不同而已。到了抽象工厂模式,一个具体的工厂里面可以生产不同种类的商品,但一种种类的商品也只能生产一种,,这句话的理解的就是你要生产美得梦或者席梦思只能选择其中一种,TCL和长虹也只能选一种,灯管或闪光灯也只能选一种。但是一个缺点是无可避免的,就是抽象工厂不支持添加新的种类商品,因为当初考虑到的生产种类都已经写在了接口或抽象类里了,如果非要添加新的种类商品那只能修改代码往接口或抽象类里添加一个创建新种类商品的方法,接着子类中都得去实现了,重新编译链接了,这就违反了关闭开放原则。
总结:
工厂方法:一个非常专非常专的专卖店,ta只能生产一类商品中的一种的商品
抽象工厂:一个非常专的专卖店,ta可以生产各类商品构成一个商品簇,但是每一类商品ta也是只能生产一种
好了,朋友们,23种设计模式分为三大组,分别为创建型模式、行为型模式以及结构型模式,加上我们之前介绍的单例模式和今天的工厂方法模式以及抽象工厂模式都是创建型模式,那么创建型模式只剩下最后两种了,ta们分别是生成器模式和原型模式。笔者不知道通过这种方式,是否能给大家带来帮助,如果可以,那我的目的就达到了,最后给各位朋友提醒一下:千万别停留在代码的实现上,如果只停留咋代码上的话满分100分只能打50分,你要知道的是,设计模式万变不离其中,无非就是多态的灵活运用,但每个设计模式有各自的适用场合,你要分清各个模式他实现什么弹性功能以及貌似类似模式之间的区别,这才是重点!