1. 简单工厂模式:http://blog.csdn.net/weixingstudio/article/details/7234423
2. 工厂方法模式:http://blog.csdn.net/weixingstudio/article/details/7234700
声明:本文章参考引用《C#设计模式》(科学出版社)一书。
抽象工厂(Abstract Factory)模式,是比工厂模式更高一层的抽象。在希望返回对象的几个相关类中的一个时,可以使用该模式,每个类都能够根据需要返回几个不同的对象。换句话说,抽象工厂是一个工厂对象,其返回几组类中的一组。
更形象的说,抽象工厂模式需要存在一个抽象工厂,然后每个具体的工厂继承这个设计好的抽象工厂,每个具体工厂可以根据需要返回自己需要的类,具体工厂通过抽象工厂返回不同的类。
下面举个具体的例子。
在一块土地上设计一个园地,我们可以把园地设计成一年生的植物园,也可以设计成菜园或者多年生的植物园。不论设计成哪一种园地,都会设计到这样的一些问题:哪些植物应该种在边上,哪些植物适宜种在中间,哪些植物是喜阴的特性等等。
我们设计一个Garden的类作为一个抽象工厂,这个类中包含了植物的可能的种类,然后实现这个类的具体工厂就可以根据需要生成不同植物的实例。
抽象工厂Garden类的设计:
using System; using System.Drawing ; namespace Gardener { /// <summary> /// Summary description for Garden. /// </summary> public class Garden { protected Plant center, shade, border; protected bool showCenter, showShade, showBorder; //select which ones to display public void setCenter() {showCenter = true;} public void setBorder() {showBorder =true;} public void setShade() {showShade =true;} //draw each plant public void draw(Graphics g) { if (showCenter) center.draw (g, 100, 100); if (showShade) shade.draw (g, 10, 50); if (showBorder) border.draw (g, 50, 150); } } }
在Garden类中,可以看到抽象工厂可以包含的Plant类的种类有center,shade,border三种类型。
Plant类的设计简单的给出如下:
using System; using System.Drawing; namespace Gardener { /// <summary> /// Summary description for Plant. /// </summary> public class Plant { private string name; private Brush br; private Font font; public Plant(string pname) { name = pname; //save name font = new Font ("Arial", 12); br = new SolidBrush (Color.Black ); } //------------- public void draw(Graphics g, int x, int y) { g.DrawString (name, font, br, x, y); } } }
Plant类中的draw()方法是用来在显示区域绘制文字的。
Garden这一作为接口的类是抽象工厂,其中定义了类的方法,继承了Garden类的具体工厂能够返回Garden类中规定的类的几个,这里,Garden类规定的返回的类可以有center,shade,border三种类型。
在继承Garden类的子类中,可以根据自己的需要返回需要的Plant类,下面给出Garden的一个子类的定义,VeggieGarden类的定义如下:
using System; namespace Gardener { /// <summary> /// Summary description for VeggieGarden. /// </summary> public class VeggieGarden : Garden { public VeggieGarden() { shade = new Plant("Broccoli"); border = new Plant ("Peas"); center = new Plant ("Corn"); } } }
PerennialGarden类的定义如下:
using System; namespace Gardener { /// <summary> /// Summary description for PerennialGarden. /// </summary> public class PerennialGarden : Garden { public PerennialGarden() { shade = new Plant("Astilbe"); border = new Plant ("Dicentrum"); center = new Plant ("Sedum"); } } }
AnnualGarden类的定义如下:
using System; using System.Drawing ; namespace Gardener { /// <summary> /// Summary description for AnnualGarden. /// </summary> public class AnnualGarden : Garden { public AnnualGarden () { shade = new Plant("Coleus"); border = new Plant ("Alyssum"); center = new Plant ("Marigold"); } } }
这三个Garden类的子类,都生成了shade ,border ,center 三个Plant类型,这就是实现了具体工厂通过抽象工厂返回不同的类,这里为了简便起见,让这三个具体工厂返回的类型都包含三种Plant类型,每一个具体工厂返回的shade都不相同,即为根据需要返回不同的对象。而且三个工厂也可以根据需要返回部分Garden类中规定的Plant类型。比如AnnualGarden 可以只返回shade和border,而不生成center的实例。
类的结构关系视图:
我们在图像狂内部绘制圆圈来表示阴影区,并且让各个植物绘制自己的文字,并不是在主窗口中直接绘制,而是在主窗口中包含的PictureBox类中添加一个绘图方法,这就要重写底层空间类的基础OnPaint事件。
using System; using System.Collections; using System.ComponentModel; using System.Drawing; using System.Data; using System.Windows.Forms; namespace Gardener { /// <summary> /// Summary description for GdPic. /// </summary> public class GdPic : System.Windows.Forms.PictureBox { /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.Container components = null; private Brush br; private Garden gden; private void init () { br = new SolidBrush (Color.LightGray ); } public GdPic() { // This call is required by the Windows.Forms Form Designer. InitializeComponent(); init(); } public void setGarden(Garden garden) { gden = garden; } protected override void OnPaint ( PaintEventArgs pe ){ Graphics g = pe.Graphics; g.FillEllipse (br, 5, 5, 100, 100); if(gden != null) gden.draw (g); } /// <summary> /// Clean up any resources being used. /// </summary> protected override void Dispose( bool disposing ) { if( disposing ) { if(components != null) { components.Dispose(); } } base.Dispose( disposing ); } #region Component Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { // // GdPic // } #endregion } }
在单选框按钮事件被触发后,就可以根据按钮的类型生成不同的具体工厂,这样具体工厂就根据抽象工厂以及自己的需要生成不同的Plant类。
private void opAnnual_CheckedChanged(object sender, EventArgs e) { setGarden( new AnnualGarden ()); } //----- private void opVegetable_CheckedChanged(object sender, EventArgs e) { setGarden( new VeggieGarden ()); } //----- private void opPerennial_CheckedChanged(object sender, EventArgs e) { setGarden( new PerennialGarden ()); } //----- private void setGarden(Garden gd) { garden = gd; //save current garden gdPic1.setGarden ( gd); //tell picture bos gdPic1.Refresh (); //repaint it ckCenter.Checked =false; //clear all ckBorder.Checked = false; //check ckShade.Checked = false; //boxes }
当某个复选框呗选中时,设置某个Plant的可见性,然后调用重绘功能,在显示区域绘制文字。
private void ckCenter_CheckedChanged(object sender, System.EventArgs e) { garden.setCenter (); gdPic1.Refresh (); } //----- private void ckBorder_CheckedChanged(object sender, System.EventArgs e) { garden.setBorder(); gdPic1.Refresh (); } //----- private void ckShade_CheckedChanged(object sender, System.EventArgs e) { garden.setShade (); gdPic1.Refresh (); }
抽象工厂的优点:
抽象工厂非常大的优点就是可以非常容易的添加新的子类。即具体工厂的类型可以非常容易的添加,例如可以添加玫瑰花园或者野花园。
抽象工厂的主要目的之一就是隔离所生成的具体类,这些类的真正类名被隐藏在工厂内部,完全不需要让客户端层面知道。
虽然抽象工厂生成的所有子类都有共同的基类,不过并不能防止这一点,即一些子类有着与其他类并不相同的一些方法。比如有些子类添加了自己的方法,这带来了在所有子类都会发生的一个问题:除非已经知道子类是否支持这些方法,否则就不能确定是否能够调用类的方法。
这一问题有两种解决方法:1.可以在基类中定义所有的方法,即使他们并不是总有实际作用。
2. 提取一个新的基本接口,该接口包含所有需要的方法,然后将所有的具体工厂类作为该接口的子类,即实现该接口。