C#设计模式之3——抽象工厂模式

来源:互联网 发布:什么是大数据服务 编辑:程序博客网 时间:2024/05/21 09:48

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 displaypublic void setCenter() {showCenter = true;}public void setBorder() {showBorder =true;}public void setShade() {showShade =true;}//draw each plantpublic 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 namefont = 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 gardengdPic1.setGarden ( gd);//tell picture bosgdPic1.Refresh ();//repaint itckCenter.Checked =false;//clear allckBorder.Checked = false;//checkckShade.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. 提取一个新的基本接口,该接口包含所有需要的方法,然后将所有的具体工厂类作为该接口的子类,即实现该接口。

原创粉丝点击