设计模式学习笔记之 Bridge 

     Bridge模式是一种将抽象部分与它的实现部分分离,使它们都可以独立地变化的设计模式。通过Bridge模式,我们可以应对类型在多个维度上发生的变化。

     我们一个食堂的例子。在食堂有两种套餐,Meal_A和Meal_B,同时有在食堂吃和带走两种可能。对应这种情况,我们一般会先想到这样的解决方法:

     public abstract class Meal
     
{
         
public abstract void Heat();
         
public abstract void PutInContainer();
     }

     
public class Meal_A:Meal
     
{
         
public override void Heat()
         
{
              
//do sth
         }

         
public override void PutInContainer()
         
{
              
//do sth
         }

     }

     
public class Meal_B:Meal
     
{
         
public override void Heat()
         
{
              
//do sth
         }

         
public override void PutInContainer ()
         
{
              
//do sth
         }

     }

     
public class Meal_A_ForSendOut:Meal_A
     
{
         
public override void Heat()
         
{
              
//do sth
         }

         
public override void PutInContainer ()
         
{
              
//do sth
         }

     }

     
public class Meal_A_ForRestaurant:Meal_A
     
{
         
public override void Heat()
         
{
              
//do sth
         }

         
public override void PutInContainer ()
         
{
              
//do sth
         }

     }

     
public class Meal_B_ForSendOut:Meal_B
     
{
         
public override void Heat()
         
{
              
//do sth
         }

         
public override void PutInContainer ()
         
{
              
//do sth
         }

     }

     
public class Meal_B_ForRestaurant:Meal_B
     
{
         
public override void Heat()
         
{
              
//do sth
         }

         
public override void PutInContainer ()
         
{
              
//do sth
         }

     }


     这里我们先创建一个虚基类Meal,两种套餐Meal_A和Meal_B都继承自这个基类。因为又有在食堂吃和带走两种可能,对于加热和装盘来说又会有不同之处,比如带走的要加热的热一些,用方便饭盒来装等等。因此每种套餐又分为两种。而且对于每一种套餐来说,可能都需要写大量的重复代码。最重要的是如果我们现在又有了一种新的可能性,例如饭在食堂吃菜带走 (对于这个例子我也很无奈,举得不是那么好…),那么对于每一种套餐,我们都要给它加上这么一种可能性,工作量是十分巨大的。

     之所以会造成这种问题的主要原因是Meal可以在两个维度上发生变化:套餐和吃法。我们的最终目的就是要将抽象和实现部分分离,因此我们也要将点餐和吃法分离。

public abstract class MealPlatformImplementation
{
         
public abstract void DoHeat();
         
public abstract void DoPutInContainer();
}

     我们设计一个虚基类MealPlatformImplementation来做不同的吃法的基类。下面列出了两种吃法,它们继承自基类,并分别在加热和装盘上做一些工作。

     public class Meal_ForSendOut_Imp:MealPlatformImplementation
{
         
public override void DoHeat()
         
{
              Console.WriteLine(
"out heat");
         }

         
public override void DoPutInContainer()
         
{
              Console.WriteLine(
"out put");
         }

}

     
public class Meal_ForRestaurant_Imp:MealPlatformImplementation
{
         
public override void DoHeat()
         
{
              Console.WriteLine(
"Restaurant heat");
         }

         
public override void DoPutInContainer()
         
{
              Console.WriteLine(
"Restaurant put");
         }

}


      我们的Meal基类现在变成这样了

public abstract class Meal
{
         
protected MealPlatformImplementation mealImp;
         
public Meal(MealPlatformImplementation mealImp)
         
{
              
this.mealImp = mealImp;
         }

         
public abstract void Heat();
         
public abstract void PutInContainer();
}


     构造函数Meal引入一个MealPlatformImplementation型参数,对基类中的MealPlatformImplementation型对象进行初始化。两种套餐继承自此基类。

public class Meal_A:Meal
{
         
public Meal_A(MealPlatformImplementation mealImp):base(mealImp)
         
{
         }

         
public override void Heat()
         
{
              mealImp.DoHeat();
         }

         
public override void PutInContainer()
         
{
              mealImp.DoPutInContainer();
         }

     }

     
public class Meal_B:Meal
     
{
         
public Meal_B(MealPlatformImplementation mealImp):base(mealImp)
         
{
         }

         
public override void Heat()
         
{
              mealImp.DoHeat();
         }

         
public override void PutInContainer()
         
{
              mealImp.DoPutInContainer();
         }

}

     现在Meal系列已经不用关心顾客吃法的问题了,那个工作已经转移到MealPlatformImplementation类中完成了,此时抽象和实现就实现了分离。

     我们可以试着使用一下我们的设计

MealPlatformImplementation newMealImp = new Meal_ForRestaurant_Imp();
Meal newMeal 
= new Meal_A(newMealImp);
newMeal.Heat();
newMeal.PutInContainer();

     这样我们就完成了一个在食堂吃的A餐的工作了,当我们要改变吃法的时候我们可以改变MealPlatformImplementation,而改变套餐时候改变Meal,不会因为顾客改变吃法而使Meal都发生改变。而且现在如果出现第三种吃法,我们只要添加一个继承自MealPlatformImplementation的新类就可以了,对于所有套餐不必全部特殊处理。

参考  MSDN WebCast  C#设计模式纵横谈     李建忠

     回到目录
  

posted on 2006-09-10 17:10  aiya  阅读(258)  评论(0)    收藏  举报