定义:
工厂方法:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个.工厂方法让类把实例化推迟到子类
抽象工厂模式:提供一个接口,用于创建相关或依赖具体对象的家族,而不需要明确指定具体类.
要点:
- 所有的工厂都是用来封装对象的创建
- 简单工厂,虽然不是真正的设计模式,但仍不失位一个简单的办法,可以将客户程序从具体类中解耦出来
- 工厂方法使用继承:把对象的创建委托给子类,子类实现工厂方法来创建对象
- 抽象工厂使用对象组合:对象的实现被实现在工厂接口所暴露出来的方法
- 所有工厂模式都通过减少应用程序和具体类之间的依赖进行松耦合
- 工厂方法允许类将实例化延迟到子类进行
- 抽象工厂创建相关的对象家族,而不需要依赖他们的具体类
- 依赖导致原则,指导我们避免依赖具体类型,而要尽量依赖抽象
- 工厂是很有威力的技巧,帮助我们针对抽象编程,而不要针对具体编程
个人理解:
当我们在一个类中,使用另一个时,往往是通过new的方式new出来的这个类的实例,然后再进行使用.这其中即使我们使用的类有抽象类或接口,但仍免不了出现 absclass c = new subclass()这样一种情况.于是,就出现了耦合;实际上,我们要如何才能处理这样一个问题,实现解耦呢?
想想我们在实际生活中接触的计算机,这个例子也许可以说明一点问题.计算机有主板,硬盘,光驱,内存,显示器,鼠标,键盘等几个零部件构成.我们在使用时是将硬盘、光驱、内存、显示器、鼠标、键盘插在了主板上,就可以使用了。而不是让主板new出一个硬盘,然后再使用硬盘,也不是让主板new出一个光驱,然后再使用光驱.而是让外界提供一个new好的硬盘,然后插给主板的硬盘接口上即可.
如下:
public class MainBoard { private HardDisk1 hd; public MainBoard() { // //TODO: 在此处添加构造函数逻辑 // } public MainBoard(HardDisk1 hd) { this.hd = hd; } public void ReadHD() { hd.Read(); } } /// <summary> /// HardDisk1为某一个具体品牌的硬盘 /// </summary> public class HardDisk1 { public void Read() { HttpContext.Current.Response.Write("HardDisk1 is reading.<br/>"); } } ---------------------------------------- protected void Page_Load(object sender, EventArgs e) { HardDisk1 hd = new HardDisk1(); MainBoard mainboard = new MainBoard(hd); mainboard.ReadHD(); }
但是,此时还是没有解耦,主板是面向的HardDisk1来运行的.如何面向其他的硬盘呢.此时可以使用抽象类和简单工厂,如下:public class MainBoard { private HardDisk hd; public MainBoard() { // //TODO: 在此处添加构造函数逻辑 // } public MainBoard(HardDisk hd) { this.hd = hd; } public HardDisk Hd { get { return this.hd; } set { this.hd = value; } } public void ReadHD() { hd.Read(); } } public abstract class HardDisk { public abstract void Read(); } /// <summary> /// HardDisk1为某一个具体品牌的硬盘 /// </summary> public class HardDisk1 : HardDisk { public override void Read() { HttpContext.Current.Response.Write("HardDisk1 is reading.<br/>"); } } /// <summary> /// HardDisk1为某一个具体品牌的硬盘 /// </summary> public class HardDisk2 : HardDisk { public override void Read() { HttpContext.Current.Response.Write("HardDisk2 is reading.<br/>"); } } public class HardDiskSimpleFactory { public HardDisk CreateHardDisk(string type) { if (type.ToLower() == "harddisk1") { return new HardDisk1(); } else { return new HardDisk2(); } } } ------------------------------------------------------ protected void Page_Load(object sender, EventArgs e) { HardDiskSimpleFactory hdsf = new HardDiskSimpleFactory(); HardDisk hd1 = hdsf.CreateHardDisk("harddisk1"); MainBoard mainboard = new MainBoard(hd1); mainboard.ReadHD(); HardDisk hd2 = hdsf.CreateHardDisk("harddisk2"); mainboard.Hd = hd2; mainboard.ReadHD(); }查看此时,主板和硬盘是否已经解耦,主板是不是没有new硬盘,也没有针对具体的硬盘进行读操作?此时我们使用的是简单工厂,简单工厂不是一个模式,而是我们在使用中养成的一个习惯.
此时再看,主板和硬盘是已经解耦了,但是看看HardDiskSimpleFactory类是否违背了开放-封闭原则.
开放-封闭原则是对扩展开放,对修改关闭,此时,如果我们新增加了一个硬盘类型HardDisk3的话,是不是又要对HardDiskSimpleFactory类进行修改呢?如果能避免再扩展类的同时,又对这个类进行修改?此时我们就要使用工厂方法模式.
代码修改如下:
public abstract class HardDiskFactory { public abstract HardDisk CreateHardDisk(); } public class HardDisk1Factory : HardDiskFactory { public override HardDisk CreateHardDisk() { return new HardDisk1(); } } public class HardDisk2Factory : HardDiskFactory { public override HardDisk CreateHardDisk() { return new HardDisk2(); } } ------------------------------------------------ protected void Page_Load(object sender, EventArgs e) { HardDiskFactory hdsf1 = new HardDisk1Factory(); HardDisk hd1 = hdsf1.CreateHardDisk(); MainBoard mainboard = new MainBoard(hd1); mainboard.ReadHD(); HardDiskFactory hdsf2 = new HardDisk2Factory(); HardDisk hd2 = hdsf2.CreateHardDisk(); mainboard.Hd = hd2; mainboard.ReadHD(); }
此时,已经基本不再违背开放-封闭原则,如果我们现在有了新的硬盘类型HardDisk3,那我们该怎么办呢?
//新增一个硬盘类型HardDisk3 public class HardDisk3 : HardDisk { public override void Read() { HttpContext.Current.Response.Write("HardDisk3 is reading.<br/>"); } } //新增一个工厂HardDisk3Factory public class HardDisk3Factory : HardDiskFactory { public override HardDisk CreateHardDisk() { return new HardDisk3(); } } ------------------------------------------------- protected void Page_Load(object sender, EventArgs e) { HardDiskFactory hdsf1 = new HardDisk1Factory(); HardDisk hd1 = hdsf1.CreateHardDisk(); MainBoard mainboard = new MainBoard(hd1); mainboard.ReadHD(); HardDiskFactory hdsf2 = new HardDisk2Factory(); HardDisk hd2 = hdsf2.CreateHardDisk(); mainboard.Hd = hd2; mainboard.ReadHD(); HardDiskFactory hdsf3 = new HardDisk3Factory(); HardDisk hd3 = hdsf3.CreateHardDisk(); mainboard.Hd = hd3; mainboard.ReadHD(); }此时,我们添加了一个类型的硬盘,也不再修改原来的硬盘生成方法,从而遵循了开放封闭原则.如果我们再提出新的需求,即:我们购买品牌机,此时机器的主板,内存,硬盘,光驱等零部件都是由该品牌机的子工厂或相关原料工厂生产的,也就意味着我们需要同一系列的内存,硬盘,光驱等零件,那么我们就可以采用抽象工厂方法来解决这个问题.我们再次改造工厂,代码如下:首先是硬盘类,没有变化,如下: public abstract class HardDisk { public abstract void Read(); } /// <summary> /// HardDisk1为某一个具体品牌的硬盘 /// </summary> public class HardDisk1 : HardDisk { public override void Read() { HttpContext.Current.Response.Write("HardDisk1 is reading.<br/>"); } } /// <summary> /// HardDisk1为某一个具体品牌的硬盘 /// </summary> public class HardDisk2 : HardDisk { public override void Read() { HttpContext.Current.Response.Write("HardDisk2 is reading.<br/>"); } }下面我们新建光驱类,光驱肯定也不只一种类型,可能一个品牌就会有一种类型的光驱:public abstract class CD_ROM { public abstract void Read(); } public class CD_ROM1 : CD_ROM { public override void Read() { HttpContext.Current.Response.Write("CD_ROM1 is Reading CD.<br/>"); } } public class CD_ROM2 : CD_ROM { public override void Read() { HttpContext.Current.Response.Write("CD_ROM2 is Reading CD.<br/>"); } }此时,我们再次建立工厂类,此时的工厂要是生产的话,需要生产一个系列的产品,具体如下:
public abstract class HardWareFactory { public abstract HardDisk CreateHardDisk(); public abstract CD_ROM CreateCD_ROM(); } public class HardWare1Factory : HardWareFactory { public override HardDisk CreateHardDisk() { return new HardDisk1(); } public override CD_ROM CreateCD_ROM() { return new CD_ROM1(); } } public class HardWare2Factory : HardWareFactory { public override HardDisk CreateHardDisk() { return new HardDisk2(); } public override CD_ROM CreateCD_ROM() { return new CD_ROM2(); } }重新再写主板类:public class MainBoard { private HardDisk hd; private CD_ROM cdrom; public MainBoard(HardDisk hd,CD_ROM cdrom) { this.hd = hd; this.cdrom = cdrom; } public HardDisk HD { get { return this.hd; } set { this.hd = value; } } public CD_ROM CD_ROM { get { return this.cdrom; } set { this.cdrom = value;} } public void ReadHD() { hd.Read(); } public void ReadCD_ROM() { cdrom.Read(); } }这是,我们的客户端再调用时,如下:
protected void Page_Load(object sender, EventArgs e) { HardWareFactory hwf = new HardWare1Factory(); HardDisk hd = hwf.CreateHardDisk(); CD_ROM cdrom = hwf.CreateCD_ROM(); MainBoard board = new MainBoard(hd, cdrom); board.ReadCD_ROM(); board.ReadHD(); hwf = new HardWare2Factory(); hd = hwf.CreateHardDisk(); cdrom = hwf.CreateCD_ROM(); board = new MainBoard(hd, cdrom); board.ReadCD_ROM(); board.ReadHD(); }页面效果如下:
至此,关于三个工厂,已经介绍完了.胡乱小结一下:
简单工厂:封装变化,创建对象,返回给客户使用.
工厂方法:封装变化,创建对象,返回给客户使用.同时避免了违反开放-封闭原则.
抽象工厂:创建一系列的对象,将创建好的对象返回给客户使用,同时遵循了开放-封闭原则.