• 设计模式 桥接模式(Bridge Pattern)


      桥接模式有点像适配器模式,都是用一个类将一种接口转换成另一种接口。但是适配器模式的意图是:是一个或多个类的接口看起来像一个特定的接口。桥接模式将类的接口和它的实现分离,无需修改客户端代码就可以改变或替换实现过程。
      桥接模式的参与这又Abstraction,他定义类的接口,Refined Abstraction,他扩展实现由Abstraction定义的接口;Implementor,它定义实现 的接口;
    ConcreteImplementor,他是实现类。
      假设我们有一个程序,要在窗口中显示一系列的产品。最简单的就是用ListBox,但在售出大量产品后,我们希望在产品中显示产品名称以及销售数目。桥接接接口 我们定义一个简单的接口,他保留着相同的部分而不管实际实现类的类型和复杂性。先定义Bridger接口,该类只接收数据ArrayList,并将其传递给现实类。

    using System;
    using System.Collections ;
    namespace BasicBridge
    {
    /// <summary>
    /// Summary description for Bridger.
    /// </summary>
    //Bridge interface to display list classes
    public interface Bridger {
    void addData(ArrayList col);
    }
    }

      还要定义一个Product类,它包含产品的名字,数量,并分析来自于数据文件输入串。

     1 using System;
    2
    3 namespace BasicBridge
    4 {
    5 /// <summary>
    6 /// Summary description for Product.
    7 /// </summary>
    8 public class Product : IComparable {
    9 private string quantity;
    10 private string name;
    11 //-----
    12 public Product(string line) {
    13 int i = line.IndexOf ("--");
    14 name =line.Substring (0, i).Trim ();
    15 quantity = line.Substring (i+2).Trim ();
    16 }
    17 //-----
    18 public string getQuantity() {
    19 return quantity;
    20 }
    21 //-----
    22 public string getName() {
    23 return name;
    24 }
    25 //-----
    26 public int CompareTo(object p) {
    27 Product prod =(Product) p;
    28 return name.CompareTo (prod.getName ());
    29 }
    30 }
    31 }

      桥接模式的另一部分是实现类,他们常常都有一个更灵活,低层次的接口。这里让实现类向显示屏幕添加数据行,一次添加一行数据。

     1 using System;
    2
    3 namespace BasicBridge
    4 {
    5 /// <summary>
    6 /// Summary description for VisList.
    7 /// </summary>
    8 public interface VisList {
    9 //add a line to the display
    10 void addLine(Product p);
    11 //remove a line from the display
    12 void removeLine(int num);
    13 }
    14 }

      左边的接口和右边的实现之间的桥梁ListBridge类,他实例化其中一个列表信息。注意,他实现了Bridger接口供应用程序使用。

     1 using System;
    2 using System.Collections ;
    3 namespace BasicBridge
    4 {
    5 /// <summary>
    6 /// Summary description for ListBridge.
    7 /// </summary>
    8 public class ListBridge : Bridger {
    9 protected VisList vis;
    10 //------
    11 public ListBridge(VisList v) {
    12 vis = v;
    13 }
    14 //-----
    15 public virtual void addData(ArrayList ar) {
    16 for(int i=0; i< ar.Count ; i++) {
    17 Product p = (Product)ar[i];
    18 vis.addLine (p);
    19 }
    20 }
    21 }
    22 }

      注意,我们把VisList的变量设为保护的,把addData方法声明为虚函数,这样以后就可以扩展这个类了。在程序设计顶层,只是用ListBridge类创建一个表实例和一个列表实例。

     1         private void init() {
    2 products = new ArrayList ();
    3 readFile(products); //read in the data file
    4        //create the product list
    5 prodList = new ProductList (lsProd);
    6 //Bridge to product VisList
    7 Bridger lbr = new SortBridge (prodList);
    8 //put the data into the product list
    9 lbr.addData (products);
    10 //create the grid VisList
    11 gridList = new GridList(grdProd);
    12 //Bridge to the grid list
    13 Bridger gbr = new SortBridge (gridList);
    14 //put the data into the grid display
    15 gbr.addData (products);
    16 }

     VisList类

      两个VisList实际上非常类似,消费者版本是类对ListBox操作,并将名字加入其中。

     1 using System;
    2 using System.Windows.Forms;
    3 namespace BasicBridge
    4 {
    5 /// <summary>
    6 /// Summary description for ProductList.
    7 /// </summary>
    8 //A VisList class for the ListBox
    9 public class ProductList : VisList {
    10 private ListBox list;
    11 //-----
    12 public ProductList(ListBox lst) {
    13 list = lst;
    14 }
    15 //-----
    16 public void addLine(Product p) {
    17 list.Items.Add (p.getName() );
    18 }
    19 //-----
    20 public void removeLine(int num) {
    21 if(num >=0 && num < list.Items.Count ){
    22 list.Items.Remove (num);
    23 }
    24 }
    25 }
    26 }

      除了要向表中的两个列表添加产品名称和数量外,VisList的GridList版本与上面的类似。

     1 using System;
    2 using System.Windows.Forms;
    3 using System.Data;
    4 namespace BasicBridge
    5 {
    6 /// <summary>
    7 /// Summary description for GridList.
    8 /// </summary>
    9 public class GridList:VisList {
    10 private DataGrid grid;
    11 private DataTable dtable;
    12 private GridAdapter gAdapter;
    13 //-----
    14 public GridList(DataGrid grd) {
    15 grid = grd;
    16 dtable = new DataTable("Products");
    17 DataColumn column = new DataColumn("ProdName");
    18 dtable.Columns.Add(column);
    19 column = new DataColumn("Qty");
    20 dtable.Columns.Add(column);
    21 grid.DataSource = dtable;
    22 gAdapter = new GridAdapter (grid);
    23 }
    24 //-----
    25 public void addLine(Product p) {
    26 gAdapter.Add (p);
    27 }
    28 //-----
    29 public void removeLine(int num) {
    30
    31 }
    32 }
    33 }


    扩展Bridge

      现在假设,需要在列表显示数据的方式做了修改。例如以字母顺序显示产品。读者可能会想修改子列表和表格类,这很容易导致不易维护,特别是如果在某个时候需要两个以上这样的显示时。我们换中做法,派生一个类似于ListBridge的心类SortBridge。为了对Product对象进行排序,让Product类是实现IComparable接口,木的事让他拥有CompareTo方法。

     1 using System;
    2
    3 namespace BasicBridge
    4 {
    5 /// <summary>
    6 /// Summary description for Product.
    7 /// </summary>
    8 public class Product : IComparable {
    9 private string quantity;
    10 private string name;
    11 //-----
    12 public Product(string line) {
    13 int i = line.IndexOf ("--");
    14 name =line.Substring (0, i).Trim ();
    15 quantity = line.Substring (i+2).Trim ();
    16 }
    17 //-----
    18 public string getQuantity() {
    19 return quantity;
    20 }
    21 //-----
    22 public string getName() {
    23 return name;
    24 }
    25 //-----
    26 public int CompareTo(object p) {
    27 Product prod =(Product) p;
    28 return name.CompareTo (prod.getName ());
    29 }
    30 }
    31 }

      有了上述改动之后,Product对象的排序就很简单了。

     1 using System;
    2 using System.Collections ;
    3 namespace BasicBridge
    4 {
    5 /// <summary>
    6 /// Summary description for SortBridge.
    7 /// </summary>
    8 public class SortBridge:ListBridge {
    9 //-----
    10 public SortBridge(VisList v):base(v){
    11 }
    12 //-----
    13 public override void addData(ArrayList ar) {
    14 int max = ar.Count ;
    15 Product[] prod = new Product[max];
    16 for(int i=0; i< max ; i++) {
    17 prod[i] = (Product)ar[i];
    18 }
    19 for(int i=0; i < max ; i++) {
    20 for (int j=i; j < max; j++) {
    21 if(prod[i].CompareTo (prod[j])>0) {
    22 Product pt = prod[i];
    23 prod[i]= prod[j];
    24 prod[j] = pt;
    25 }
    26 }
    27 }
    28 for(int i = 0; i< max; i++) {
    29 vis.addLine (prod[i]);
    30 }
    31 }
    32 }
    33 }

      排序结果如下图

      这清楚的表明,不用修改实现就能改变接口,反过来也一样。例如创建一个其他类型的类表显示类并替换当前的显示,只要新的列表也实现了VisList接口,就不需要改变其他程序了。下面是TreeList类。

     1 using System;
    2 using System.Windows.Forms;
    3 using System.Data;
    4 namespace BasicBridge
    5 {
    6 /// <summary>
    7 /// Summary description for GridList.
    8 /// </summary>
    9 public class TreeList:VisList {
    10 private TreeView tree;
    11 private TreeAdapter gAdapter;
    12 //-----
    13 public TreeList(TreeView tre) {
    14 tree = tre;
    15 gAdapter = new TreeAdapter (tree);
    16 }
    17 //-----
    18 public void addLine(Product p) {
    19 gAdapter.Add (p);
    20 }
    21 //-----
    22 public void removeLine(int num) {
    23 }
    24 }
    25 }

      注意,我们利用前一张编写的TreeAdapter类,并修改它使之能对Product对象操作。创建一个树形列表组件,他实现了VisList接口,并替换原来的列表而没有修改类的公共接口。

     1 using System;
    2 using System.Windows.Forms;
    3 namespace BasicBridge
    4 {
    5 /// <summary>
    6 /// Summary description for TreeAdapter.
    7 /// </summary>
    8 public class TreeAdapter {
    9 private TreeView tree;
    10 //------
    11 public TreeAdapter(TreeView tr) {
    12 tree=tr;
    13 }
    14 //------
    15 public void Add(Product p) {
    16 TreeNode nod;
    17 //add a root node
    18 nod = tree.Nodes.Add(p.getName());
    19 //add a child node to it
    20 nod.Nodes.Add(p.getQuantity ());
    21 tree.ExpandAll ();
    22 }
    23 //------
    24 public int SelectedIndex() {
    25 return tree.SelectedNode.Index ;
    26 }
    27 //------
    28 public void Clear() {
    29 TreeNode nod;
    30 for (int i=0; i< tree.Nodes.Count ; i++) {
    31 nod = tree.Nodes [i];
    32 nod.Remove ();
    33 }
    34 }
    35 //------
    36 public void clearSelection() {}
    37 }
    38 }

    效果如下图

    桥接模式的效果
    1.桥接模式可以保持客户端程序接口不变,而允许读者修改显示类,或要使用的类。可以防止重新编译一系列复杂的用户接口模块,只需要重新编译Bridge和实际的最终显示类。
    2.可以分别扩展实现类和Bridge类,二者之间通常不会有相互作用。
    3.对客户端程序很容易隐藏实现细节。



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

  • 相关阅读:
    深入解析Hibernate核心接口
    Hibernate基本原理
    深入hibernate的三种状态
    Hibernate commit() 和flush() 的区别
    Hibernate中的merge使用详情解说
    Record is locked by another user
    Vue路由router-link的使用
    Vue-router的基本使用
    Vue把父组件的方法传递给子组件调用(评论列表例子)
    Vue中子组件调用父组件的方法
  • 原文地址:https://www.cnblogs.com/sunjinpeng/p/2423561.html
Copyright © 2020-2023  润新知