Java设计模式--桥梁模式【Bridge Pattern】

       “老板娘,来一个圆饼加鸡蛋!...”

      今天,我要说说我的早餐。每天清晨,我都忍不住去公司前面那家超市买早餐。最让我垂涎三尺的就是他们家的饼,形式多样,口感俱佳。他们家有长条形的土豆饼,圆形的白菜饼,圆形的茄子饼,方形的鸡蛋饼,方形的香肠饼,还有大煎饼。。。

      那么我就说一说这个圆形和方形的白菜饼,鸡蛋饼,香肠饼。若采用自上而下的继承关系,程序设计时只需要定义一个抽象的“饼”,定义制作饼的加鸡蛋、加香肠、加青菜的方法,子类去继承和实现相应的方法即可。

     这种实现方式的UML图如下:

    

          类图很简单,声明了一个cake抽象类,定义一个"饼"的抽象模型,定义了制作饼的几种方式方法,不同的饼实现这些方法,源代码如下:

package com.pattern.bridge.v1;
/**
 * 有两种饼:圆饼和方饼,分别可以加三种辅料:鸡蛋、香肠、青菜
 * 饼--抽象类:定义饼的抽象方法,每一种继承“饼”的子类都需要实现所有抽象方法
 * 根据不同的抽象方法,实现“饼”的不同制作方式
 * 
 * 第一种实现方式:
 * 把圆饼、方饼分别加鸡蛋、香肠、青菜的各备上一些,客户需要时直接拿给TA
 * @author 
 *
 */
public abstract class Cake {
    protected abstract void addEgg();
    protected abstract void addSausage();
    protected abstract void addGreens();
    public  void makeCake(String addWhat){
    	if(addWhat.equalsIgnoreCase("鸡蛋")){
    		this.addEgg();
    	}else if(addWhat.equalsIgnoreCase("香肠")){
    	     this.addSausage();
    	}else if(addWhat.equalsIgnoreCase("青菜")){
    		this.addGreens();
    	}
    }
}
package com.pattern.bridge.v1;
/**
 * 圆饼具体实现类--根据客户的要求提供不同的制作方法,但是无论客户选择哪种方式,其他未选择的方式也需要实现
 * @author 
 *
 */
public class RoundCake extends Cake {

	@Override
	protected void addEgg() {
       System.out.println("【圆饼】加【鸡蛋】嘞...\n");
	}

	@Override
	protected void addSausage() {
		System.out.println("【圆饼】加【香肠】嘞...\n");
	}

	@Override
	protected void addGreens() {
		System.out.println("【圆饼】加【青菜】嘞...\n");
	}
} 

package com.pattern.bridge.v1;
/**
 * 方饼具体实现类--根据客户的要求提供不同的制作方法,但是无论客户选择哪种方式,其他未选择的方式也需要实现
 * @author 
 *
 */
public class SquareCake extends Cake {

	@Override
	protected void addEgg() {
       System.out.println("【方饼】加【鸡蛋】嘞...\n");
	}

	@Override
	protected void addSausage() {
		System.out.println("【方饼】加【香肠】嘞...\n");
	}

	@Override
	protected void addGreens() {
		System.out.println("【方饼】加【青菜】嘞...\n");
	}

}
package com.pattern.bridge.v1;
/**
 * 客户端测试类:
 * 老板,给我来3个饼:一个圆饼加鸡蛋,一个方饼加香肠,另一个方饼加青菜
 * 好嘞~
 * @author 
 *
 */
public class Test {
   public static void main(String[] args){
	   Cake c1=new RoundCake();
	    c1.makeCake("鸡蛋");
	    
	    Cake c2=new SquareCake();
	    c2.makeCake("香肠");
	    
	    Cake c3=new SquareCake();
	    c3.makeCake("青菜");
   }
}
        上述代码只是描述了早餐店目前的情况,但是任何事情都是变化莫测和向前发展的,早餐店也在不断地改善和发展,比如早餐店即将推出一款新的制作方法,圆饼和方饼还可以加韩国烤肉,开张时吸引了一大批顾客。我们都是吃货呀,好吃的当然不会错过!但是如果按照上述代码的模式,我们需要新增一个子类,且原来的接口需要新增一种制作方法,继承的所有子类都需要改动。而且每一种饼都要实现这么多方式方法,可能并不一定会用到,违反了单一职责原则和依赖倒置原则。

     那么,什么样的方式可以不违背基本的设计原则,又实现上述功能呢?

    这就是我们今天要说的”桥梁模式“,所谓桥梁模式,将抽象部分和实现部分分离,各自独立,但又能动态结合。实现桥梁模式,重点是如何做到抽象化(Abstraction)实现化(Implementation)脱耦,使得二者可以独立地变化 

   •抽象化抽象化就是把不同的实体当作同样的实体对待。在面向对象中,将对象的共同性质抽取出来形成类的过程即为抽象化的过程。
   •实现化针对抽象化给出的具体实现,就是实现化,抽象化与实现化是一对互逆的概念,实现化产生的对象比抽象化更具体,是对抽象化事物的进一步具体化的产物。
   •脱耦脱耦就是将抽象化和实现化之间的耦合解脱开,或者说是将它们之间的强关联改换成弱关联将两个角色之间的继承关系改为关联关系。桥接模式中的所谓脱耦,就是指在一个软件系统的抽象化和实现化之间使用关联关系(组合或者聚合关系)而不是继承关系,从而使两者可以相对独立地变化,这就是桥接模式的用意。

   早餐饼的桥梁模式UML图如下:

   
       从类图可以看出,将”饼“和”加辅料“的动作分别抽象出来,分别独立,他们之间架起了一座桥,又能动态结合。若新增加一种类型的饼或者制作工艺,只需要在各自的体系中添加代码,具有良好的扩展性。源代码实现:

package com.pattern.bridge.v2;
/**
 * 定义“饼”的抽象类:
 * 
 * 第二种实现方式:
 * 将“饼”的种类(抽象)和制作方式(具体实现)分开,抽象出饼的种类特征和制作工艺特征,
 * 然后让每一种饼都有制作工艺接口,根据客户的需求,采用对应的工艺,制作出需要的饼
 * @author 
 *
 */
public abstract class Cake {
   protected AddImplement addImplement=null;
   
   protected void setAddImplement(AddImplement addImplement){
	   this.addImplement=addImplement;
   }
   
   public abstract void startMakeCake();
}
package com.pattern.bridge.v2;
/**
 * 饼的具体实现类--圆饼
 * @author
 *
 */
public class RoundCake extends Cake {

	@Override
	public void startMakeCake() {
		System.out.println("【圆饼】加什么呢?先备着再说吧...");
	}

}
package com.pattern.bridge.v2;
/**
 * 饼的具体实现类--方饼
 * @author
 *
 */
public class SquareCake extends Cake {

	@Override
	public void startMakeCake() {
		System.out.println("【方饼】加什么呢?先备着再说吧...");
	}

}
package com.pattern.bridge.v2;
/**
 * 饼的制作方式-抽象类:定义抽象方法,根据客户的需求来采用对应的制作工艺
 * @author 
 *
 */
public abstract class AddImplement {
protected String addWhat;

}
package com.pattern.bridge.v2;
/**
 * 饼的制作方式-加鸡蛋  具体实现类
 * @author 
 *
 */
public class AddEgg extends AddImplement {
	public AddEgg(){
		this.addWhat="鸡蛋";
		System.out.println("加【"+addWhat+"】咯...\n");
	}
}
package com.pattern.bridge.v2;
/**
 * 饼的制作方式-加香肠  具体实现类
 * @author 
 *
 */
public class AddSausage extends AddImplement {
	public AddSausage(){
		this.addWhat="香肠";
		System.out.println("加【"+addWhat+"】咯...\n");
	}
}
package com.pattern.bridge.v2;
/**
 * 饼的制作方式-加青菜  具体实现类
 * @author 
 *
 */
public class AddGreens extends AddImplement {
	public AddGreens(){
		this.addWhat="青菜";
		System.out.println("加【"+addWhat+"】咯...\n");
	}
}
package com.pattern.bridge.v2;
/**
 * 客户端测试类:
 * 老板,给我来3个饼:一个圆饼加鸡蛋,一个方饼加香肠,另一个方饼加青菜
 * 好嘞~
 * @author 
 *
 */
public class Test {
     public static void main(String[] args){
    	 Cake c1=new RoundCake();
    	 c1.startMakeCake();
         c1.setAddImplement(new AddEgg());
          
         Cake c2=new SquareCake();
         c2.startMakeCake();
         c2.setAddImplement(new AddSausage());
         
         Cake c3=new SquareCake();
         c3.startMakeCake();
         c2.setAddImplement(new AddGreens());
       
     }
}
综上所述,Bridge模式的优缺点如下:

优点:

1) 分离接口及其实现部分:一个实现未必不变地绑定在一个接口上。抽象类的实现可以在运行时刻进行配置,一个对象甚至可以在运行时刻改变它的实现。将Abstraction与Implementor分离有助于降低对实现部分编译时刻的依赖性,当改变一个实现类时,并不需要重新编译 Abstraction类和它的客户程序。为了保证一个类库的不同版本之间的二进制兼容性,一定要有这个性质。另外,接口与实现分离有助于分层,从而产生更好的结构化系统,系统的高层部分仅需知道Abstraction和Implementor即可。
2) 提高可扩充性:你可以独立地对Abstraction和Implementor层次结构进行扩充。

3 ) 实现细节对客户透明: 你可以对客户隐藏实现细节,例如共享 Implementor对象以及相应的引用计数机制(如果有的话) 。

缺点:
1)增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。
2)桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性。 



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值