Abstract Factory Pattern
首先看一下,我们要实现的程序运行效果:
*_* 先学几个单词:
broccoli : 绿花椰菜
corn : 玉米
peas : 豌豆
从运行的结果我们先说一下思路:
当Garden type不同时右边应显示不同的Garden type中的数据资料。
下面的三个checkbox是用来控制是否显示的。
为了保证程序的健壮性,考虑到Garden type可能会继续增加,也就是会继续增加新的类(相似的一系列类)。
首先我们来看一下基类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);
}
}
需要注意的基类的成员变量 3个变量的数据类型是我们自己定义的一个类:
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);
}
}
下面让我们来思考一下父类的设计,父类只是告诉我们它是一个garden但是至于这个garden里面是什么
性质的garden它则没有作出限制,可以是flower,也可以是vegetable的garden,但是它给出了三个plant类型的成员,那么子类就可以继承它,当然子类也可以声明自己的plant类型的或者其他类型的成员变量,但是如果那样的话,就违背了我们的本意。因为我们是需要产品的模板生产类似的产品就行了。
所以我们可以声明任意多个garden的子类,为了使我们的子类生产出来的产品象父类,但又能表示出该子类是不同性质的garden,wm ky 我们可以使用一个构造函数来初始化center, shade, border这三个从基类继承得到的成员字段。
请看我们得到的蔬菜型garden:
public VeggieGarden() {
shade = new Plant("Broccoli");
border = new Plant ("Peas");
center = new Plant ("Corn");
}
}
{
public PerennialGarden() {
shade = new Plant("Astilbe");
border = new Plant ("Dicentrum");
center = new Plant ("Sedum");
}
}
下面的*线中的内容是值得思考的,在书中并未提出下面的看法,但是这也是很容易想到的一点。
这里当作一个小插曲,如有不妥望大家指教。
******************************************************************************************
在这个时候很多人也许会问那么我们脑海中的所谓的“工厂类”在哪里呢?
实际上在我们上面已经用硬编码的形式生成了我们要得到的子类,这样的方式类似于枚举。
那么如果你想写一个工厂类来帮助你生产子类那么也是可行的,请看:
{
public factory(string[] namelist)
{
string[] mylist =new string[3];
Array.Copy(namelist,mylist,3);
shade = new Plant(mylist[0].ToString());
border = new Plant (mylist[1].ToString());
center = new Plant (mylist[2].ToString());
}
}
**********************************************************************************************
在demo中现已经通过手动生产子类的方法得到若干个例如蔬菜等等这样的garden.
那么现在我们就要写一个驱动程序以方便我们在适当的时候得到我们想要的garden子类。
在这里我们把它简单化:
当单击不同的checkbox的时候我们在事件关联的事件处理函数中来完成驱动的工作(生成子类):
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
}
得到Garden的子类以后把它传递给gdPic1,通知它当前所实例化的子类是哪一个类。通知它重新绘制。
当ckCenter_CheckedChanged 、ckBorder_CheckedChanged、ckShade_CheckedChanged事件处理函数被调用时,下面是事件处理函数:
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 ();
}
注意这句话,garden.setCenter ()是调用基类的一个方法
public void setCenter() {showCenter = true;}
接着:
gdPic1.Refresh ();
通知 gdpic1重绘(会调用OnPaint方法)。
在组件类GdPic中覆写了OnPaint方法,请看:
Graphics g = pe.Graphics;
g.FillEllipse (br, 5, 5, 100, 100);
if(gden != null)
gden.draw (g);
}
所以我们可以知道在OnPaint方法调用的过程中又调用了子类从基类继承得到的draw方法,而draw方法则是去调用成员变量本身的draw方法进行绘制。
希望对大家有所帮助。平静下来仔细看,如果需要demo的可以联系我。