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. 提取一个新的基本接口,该接口包含所有需要的方法,然后将所有的具体工厂类作为该接口的子类,即实现该接口。