设计模式 生成器模式(builder Pattern)

  生成器模式又称建造者模式,定义一个抽象的建造者的角色(Builder),规定所有具体的建造者都应该具有的功能——这些功能就是如何创建复杂对象的某个特定部分(子对象),而具体如何创建子对象有具体的创建者实现。再定义一个指导者的角色,它把创建者作为工具,知道如何使用这个工具来创建复杂对象。这样,客户在需要创建这个复杂对象的时候,只需要给指导者一个具体的创建者就可以了。至于具体创建者如何创建子对象的细节以及这些子对象之间的差异,不是指导者,也不是客户关心的。
  下面我们用一个例子来说明一下生成器模式,假设我们不但需要一个计算的算法,还需要一个由于显示数据根据数据不同而完全不同的用户界面。我们考虑一个简单的例子,在这个例子中,用一个类构造一个用户界面。假设我们要编写一个程序跟踪投资效益。我们有股票、基金、债券等N个投资项目,对每个投资项目都要显示持有量列表,无论对于大数量的投资(股票)还是小数目的投资(基金),都有一种易于使用的显示方式。每种情况我们都想多选显示。如果投资项目的数量大,可以使用多选列表框,如果等于或小于三个项目,则使用复选框代替。让Builder类根据需要显示项目生成的界面,同时还要有相同的方法来返回。
  我们的程序运行结构图如下,左边是少量数据,右边是大量数据。

  接下来我们考虑如何构建界面,来完成不同的显示。首先创建MultiChoice接口,里边定义了需要实现的方法。

 1 using System;
2 using System.Collections ;
3 using System.Windows.Forms;
4
5
6 /// <summary>
7 /// Summary description for MultiChoice.
8 /// </summary>
9 public interface MultiChoice
10 {
11 ArrayList getSelected();
12 void clear();
13 Panel getWindow();
14 }

  getWindow方法返回一个包含多选显示的面板(panel),这里使用两个显示面板实现该界面一个是复选框面板,一个是列表面板。

1     public class CheckChoice:MultiChoice     {

  或

1     public class ListChoice:MultiChoice {

  接下来创建一个抽象类Equities,并有它派生出Stocks(股票),Bonds(债券),Mutuals(基金)类。

 1 using System;
2 using System.Collections ;
3
4
5 /// <summary>
6 /// Summary description for Equities.
7 /// </summary>
8 public abstract class Equities {
9 protected ArrayList array;
10 public abstract string ToString();
11 //----------
12 public ArrayList getNames() {
13 return array;
14 }
15 //----------
16 public int count() {
17 return array.Count ;
18 }
19 }

  Stocks

 1 using System;
2 using System.Collections ;
3
4
5
6 /// <summary>
7 /// Summary description for Stocks.
8 /// </summary>
9 public class Stocks:Equities {
10 public Stocks() {
11 array = new ArrayList();
12 array.Add ("Cisco");
13 array.Add ("Coca Cola");
14 array.Add ("GE");
15 array.Add ("Harley Davidson");
16 array.Add ("IBM");
17 array.Add ("Microsoft");
18 }
19 public override string ToString() {
20 return "Stocks";
21 }
22 }

Bonds(债券),Mutuals(基金)类代码基本类似....

  我们还需要一个简单的类来决定,要返回的是一个复选框面板还是一个列表框面板。我们把这个类称为StockFactory。由于我们只需要该类的一个实例,因而创建该类时让其中的一个方法为静态的。我们也可以把这个类称为简单工厂。

 1 using System;
2
3
4 /// <summary>
5 /// Summary description for StockFactory.
6 /// </summary>
7 public class StockFactory
8 {
9 public static MultiChoice getBuilder(Equities stocks)
10 {
11 if (stocks.count ()<=3) {
12 return new CheckChoice (stocks);
13 }
14 else {
15 return new ListChoice(stocks);
16 }
17 }
18 }

  CheckChoice类,这里生成0-3个复选框的面板,并且将面板返回。

 1 using System;
2 using System.Collections ;
3 using System.Windows.Forms ;
4 using System.Drawing ;
5
6
7 //returns a panel of 0 to 3 check boxes
8 public class CheckChoice:MultiChoice {
9 private ArrayList stocks;
10 private Panel panel;
11 private ArrayList boxes;
12 //------
13 public CheckChoice(Equities stks) {
14 stocks = stks.getNames ();
15 panel = new Panel ();
16 boxes = new ArrayList ();
17 //add the check boxes to the panel
18 for (int i=0; i< stocks.Count; i++) {
19 CheckBox ck = new CheckBox ();
20 //position them
21 ck.Location = new Point (8, 16 + i * 32);
22 string stk = (string)stocks[i];
23 ck.Text =stk;
24 ck.Size = new Size (112, 24);
25 ck.TabIndex =0;
26 ck.TextAlign = ContentAlignment.MiddleLeft ;
27 boxes.Add (ck);
28 panel.Controls.Add (ck);
29 }
30 }
31 //------
32 //uncheck all check boxes
33 public void clear() {
34 for(int i=0; i< boxes.Count; i++) {
35 CheckBox ck = (CheckBox)boxes[i];
36 ck.Checked =false;
37 }
38 }
39 //------
40 //return list of checked items
41 public ArrayList getSelected() {
42 ArrayList sels = new ArrayList ();
43 for(int i=0; i< boxes.Count ; i++) {
44 CheckBox ck = (CheckBox)boxes[i];
45 if (ck.Checked ) {
46 sels.Add (ck.Text );
47 }
48 }
49 return sels;
50 }
51 //------
52 //return panel of checkboxes
53 public Panel getWindow() {
54 return panel;
55 }
56 }

  ListBoxChoice类,该类创建一个多选框列表,并且将其插入到一个面板中,然后显示名称。

 1 using System;
2 using System.Collections ;
3 using System.Windows.Forms ;
4 using System.Drawing ;
5
6 /// <summary>
7 /// Summary description for ListChoice.
8 /// </summary>
9 /// creates a Panel containing a list box
10 public class ListChoice:MultiChoice {
11 private ArrayList stocks;
12 private Panel panel;
13 private ListBox list;
14 //------
15 //constructor creates and loads the list box
16 public ListChoice(Equities stks) {
17 stocks = stks.getNames ();
18 panel = new Panel ();
19 list = new ListBox ();
20 list.Location = new Point (16, 0);
21 list.Size = new Size (120, 160);
22 list.SelectionMode =SelectionMode.MultiExtended ;
23 list.TabIndex =0;
24 panel.Controls.Add (list);
25 for(int i=0; i< stocks.Count ; i++) {
26 list.Items.Add (stocks[i]);
27 }
28 }
29 //returns the Panel
30 //------
31 public Panel getWindow() {
32 return panel;
33 }
34 //returns an array of selected elements
35 //------
36 public ArrayList getSelected() {
37 ArrayList sels = new ArrayList ();
38 ListBox.SelectedObjectCollection coll = list.SelectedItems ;
39 for(int i=0; i< coll.Count; i++) {
40 string item = (string)coll[i];
41 sels.Add (item );
42 }
43 return sels;
44 }
45 //------
46 //clear selected elements
47 public void clear() {
48 list.Items.Clear();
49 }
50 }

  在使用列表框的时,列表框中值不仅限于字符串,在添加的数据中,可以使具有ToString方法的任何类型的对象。

 1     private ListBox lsEquities;
2 /// <summary>
3 /// Required designer variable.
4 /// </summary>
5 private Container components = null;
6 private Button btPlot;
7 private Panel pnl;
8 private MultiChoice mchoice;
9 private void init() {
10 lsEquities.Items.Add (new Stocks());
11 lsEquities.Items.Add (new Bonds());
12 lsEquities.Items.Add (new Mutuals());
13 }
14 public WealthBuilder()
15 {
16 InitializeComponent();
17 init();
18 }

  在单击列表框中第一行数据时,单击方法会获得相应的Equities类的实例,将该实例传给MultiChoice工厂,接下来在相应的类中生成一个包含项目的面板,然后删除旧的面板,添加新的面板。

 1 private void lsEquities_SelectedIndexChanged(object sender, System.EventArgs e) {
2 int i = lsEquities.SelectedIndex ;
3 Equities eq = (Equities)lsEquities.Items[i];
4 mchoice= StockFactory.getBuilder (eq);
5 this.Controls.Remove (pnl);
6 pnl = mchoice.getWindow ();
7 setPanel();
8 }
9
10 private void setPanel() {
11 pnl.Location = new Point(152, 24);
12 pnl.Size = new Size(128, 168);
13 pnl.TabIndex = 1;
14 Controls.Add(pnl);
15 }

在本里中,我们并没有实现真正的标注,只是弹出选中的值。

 1         private void btPlot_Click(object sender, System.EventArgs e) {
2 //display the selected items in a message box
3 if(mchoice != null) {
4 ArrayList ar = mchoice.getSelected ();
5 string ans = "";
6 for(int i=0; i< ar.Count ; i++) {
7 ans += (string)ar[i] +" ";
8 }
9 MessageBox.Show (null, ans, "Selected equities", MessageBoxButtons.OK );
10 }
11 }


生成器模式效果
1.生成器允许读者改变产品的内部表示,同时也隐藏了产品的组装细节。
2.每个特定的生成器都独立于其他的生成器,同时也独立于程序的其他部分,这一点提高了对象模块性,并使用添加其他的生成器变得简单。
3.由于每个生成器是根据数据移步一步构建最终结果,所以能精确的控制生成器构建的每个结果。
生成器模式有点类似于抽象工厂,两者都是返回由许多方法和对象组成的类,他们之间的主要差别是,抽象工厂返回的是一系列相关的类,而生成器是根据提供的数据一步一步的构建一个复杂的对象。






人生如棋、我愿为卒、行动虽缓、从未退过

原文地址:https://www.cnblogs.com/sunjinpeng/p/2420862.html