设计模式-生成器模式
本篇文章来自于设计模式一书中的“生成器模式”
本篇中我们学习如何使用生成器模式从部件构建对象,假设我们不但需要一个用于计算的算法,还需要一个根据数据的不同而完全不同的用户界面,典型的例子就是E-mail地址薄,在地址薄中,即有个人信息也有组的信息,而用户希望能根据信息的不同,改变地址薄的显示, 这样在用户屏幕中能显示姓名、公司、E-mail地址和电话号码。另一方面,如果显示一个组的地址页,希望能看到组名、组的职能、成员表及他们的E-mail地址。单击一个人的时候得到一种显示方式,单击一个组的时候得到另一种显示方式。假设所有的E-mail地址都保存在Address类的一个对象里,个人和组都派生于这个基类,如下图。
我们考虑一个简单一点的例子,编写一个程序来跟踪投资的效益。我们有股票、债券和基金等投资项目,对每一种投资项目都要显示特有量的列表。无论是对大数量的投资项目(如股票)还是小数量的投资项目(如基金)都有一种易于使用的显示方式。每种情况下我们都要一种多选显示,这样就能够选择一个或多个项目来标注。如果投资项目的数量大,可以使用一个多选的列表框显示;如果只有三个或更少的项目,则使用几个复选框来表示。让Builder类根据需要显示的项目个数生成界面,同时还要有相同的方法来返回结果。完整的类图如下。
namespace BuilderPattern { public interface IMultiChoice { ArrayList GetSelected(); void Clear(); Panel GetPanel(); } }
GetPanel方法返回一个包含多选显示的面板,这里使用两个显示面板实现该界面,一个是复选框,一个是列表框。
public class ListChoice : IMultiChoice { private ArrayList Stocks; private Panel Panel; private ListBox List; public ListChoice(Equities stocks) { Stocks = stocks.GetNames(); Panel = new Panel(); List = new ListBox { Location = new Point(16, 0), Size = new Size(120, 160), SelectionMode = SelectionMode.MultiExtended }; Panel.Controls.Add(List); foreach (var stks in Stocks) List.Items.Add(stks); } public ArrayList GetSelected() { var sel = new ArrayList(); foreach (string str in List.SelectedItems) sel.Add(str); return sel; } public void Clear() { List.Items.Clear(); } public Panel GetPanel() { return Panel; } }
public class CheckChoice : IMultiChoice { ArrayList Stocks; ArrayList Boxes; Panel Panel; public CheckChoice(Equities stocks) { Boxes = new ArrayList(); Panel = new Panel(); Stocks = stocks.GetNames(); //添加checkbox到panel中 for (int i = 0, j = Stocks.Count; i < j; i++) { var chBox = new CheckBox { Location = new Point(8, 16 + i * 32), Text = Stocks[i].ToString(), Size = new Size(112, 24), TextAlign = ContentAlignment.MiddleLeft }; Boxes.Add(chBox); Panel.Controls.Add(chBox); } } public ArrayList GetSelected() { var sel = new ArrayList(); foreach (CheckBox chBox in Boxes.Cast<CheckBox>().Where(chBox => chBox.Checked)) { sel.Add(chBox.Text); } return sel; } public void Clear() { foreach (CheckBox chBox in Boxes) { chBox.Checked = false; } } public Panel GetPanel() { return Panel; } }
接下来创建一个抽象类Equities,并派生出Bonds、Mutuals、Stocks类
其余的全部代码(GetNames方法和Count方法)已在Equities中实现,Bonds与Mutuals类与此类似
public abstract class Equities { protected ArrayList Array; public ArrayList GetNames() { return Array; } public int Count() { return Array == null ? 0 : Array.Count; } }
public class Stocks : Equities { public Stocks() { Array = new ArrayList { "Cisco", "Coca Cola", "CE", "Harley Davidson", "IBM", "Microsoft" }; } public override string ToString() { return "Stocks"; } }
StockFactory
我们需要一个简单的类来决定要返回的是一个复选框界面还是一个列表界面。用设计模式的语言来讲,这个简单工厂类叫做Director,而由MultiChoice类派出来的实际类就是Builder。
public class StockFactory { public static IMultiChoice GetBuilder(Equities stocks) { if (stocks.Count() > 3) { return new ListChoice(stocks); } return new CheckChoice(stocks); } }
最终的界面如下