设计模式解密(12)- 桥接模式

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

1、简介

定义:将抽象部分与实现部分分离,使它们都可以独立的变化。

主要解决:在多维可能会变化的情况下,用继承会造成类爆炸问题,扩展起来不灵活。

何时使用:实现系统可能有多个角度分类,每一种角度都可能变化。

如何解决:把这种多角度分类分离出来,让它们独立变化,减少它们之间耦合。

注意事项:对于两个独立变化的维度,使用桥接模式再适合不过了。

英文:bridge

类型:结构型

2、问题引入

在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度?

先来试想一个情景(OA系统中的消息处理):

  消息类型:普通消息,加急消息,特急消息

  消息方式:系统内消息,手机短信,邮件

 

在不使用桥接模式的情况下(即:使用继承方式),首先我们想到的方案:为每一种消息方式都提供一套消息类型,或者为每一种消息类型都提供一套消息方式;

示意图如下:

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

或者:

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

实现代码(按第二个图实现代码逻辑)(这里区分普通,加急,特急消息,采用的是在消息头加上标记,例:*加急*:.....):

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

package com.designpattern.bridge.solution_1;/**
 * 消息统一接口
 * @author Json*/public interface Message {    /**
     * 发送消息
     * @param message 消息内容
     * @param users 接收人     */
    public void send(String message,String users);
}

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

 消息类型(3种):

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

package com.designpattern.bridge.solution_1;/**
 * 普通消息接口
 * @author Json*/public interface CommonMessage extends Message {

}

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

package com.designpattern.bridge.solution_1;/**
 * 加急消息接口
 * @author Json*/public interface UrgencyMessage extends Message {

}

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

package com.designpattern.bridge.solution_1;/**
 * 特急消息接口
 * @author Json*/public interface VeryUrgencyMessage extends Message {    
    /** 
     * 扩展自己的新功能:特急任务,需要催促接收人尽快完成
     * @param messageId 消息的编号 
     * @return
     */  
    public void urge(String messageId); 
}

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

 普通消息   对应    3种消息发送方式:

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

package com.designpattern.bridge.solution_1;/**
 * 使用站内消息方式发送【普通】信息
 * @author Json*/public class CommonSystemMessage implements UrgencyMessage {

    @Override    public void send(String message, String users) {
        message = "*普通*:" + message;
        System.out.println("使用站内消息方式,发送信息【"+message+"】To【"+users+"】");
    }
}

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

package com.designpattern.bridge.solution_1;/**
 * 使用短信方式发送【普通】信息
 * @author Json*/public class CommonMobileMessage implements UrgencyMessage {

    @Override    public void send(String message, String users) {
        message = "*普通*:" + message;
        System.out.println("使用短信方式,发送信息【"+message+"】To【"+users+"】");
    }
}

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

package com.designpattern.bridge.solution_1;/**
 * 使用邮件方式发送【普通】信息
 * @author Json*/public class CommonEmailMessage implements CommonMessage {
    
    @Override    public void send(String message, String users) {
        message = "*普通*:" + message;
        System.out.println("使用邮件方式,发送信息【"+message+"】To【"+users+"】");
    }
}

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

 紧急消息   对应    3种消息发送方式(代码类似,这里折叠了):

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训 View Code

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训 View Code

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训 View Code

 紧急消息   对应    3种消息发送方式(代码类似,这里折叠了):

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训 View Code

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训 View Code

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训 View Code

 测试代码:

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

package com.designpattern.bridge.solution_1;/**
 * 测试 
 * @author Json*/public class Client {    
    public static void main(String[] args) {
        Message s;        
        //创建普通消息
        s = new CommonEmailMessage();
        s.send("本月需完成任务如下:...", "Json_Wang"); 
        //创建一个加急消息对象 
        s = new UrgencyEmailMessage();
        s.send("本周需完成任务如下:...", "Json_Wang"); 
        //创建一个特急消息对象  
        s = new VeryUrgencyEmailMessage();  
        s.send("尽快修复致命bug,今天客户端无法登陆的问题!", "Json_Wang");
        
        System.out.println("---------------------------------");        
        //创建普通消息
          s = new CommonMobileMessage();
          s.send("本月需完成任务如下:...", "Json_Wang"); 
          //创建一个加急消息对象 
          s = new UrgencyMobileMessage();
          s.send("本周需完成任务如下:...", "Json_Wang"); 
          //创建一个特急消息对象  
          s = new VeryUrgencyMobileMessage();  
          s.send("尽快修复致命bug,今天客户端无法登陆的问题!", "Json_Wang");          
          //站内消息实现省略...    } 
}

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

 结果:

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

使用邮件方式,发送信息【*普通*:本月需完成任务如下:...】To【Json_Wang】
使用邮件方式,发送信息【*加急*:本周需完成任务如下:...】To【Json_Wang】
使用邮件方式,发送信息【*特急*:尽快修复致命bug,今天客户端无法登陆的问题!】To【Json_Wang】
---------------------------------
使用短信方式,发送信息【*普通*:本月需完成任务如下:...】To【Json_Wang】
使用短信方式,发送信息【*加急*:本周需完成任务如下:...】To【Json_Wang】
使用短信方式,发送信息【*特急*:尽快修复致命bug,今天客户端无法登陆的问题!】To【Json_Wang】

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

 上面这样实现,好像也能满足基本的功能要求,可是这么实现好不好呢?有没有什么问题呢?

试想一下:新增一种消息类型或者消息方式,我们就要实现其对应的全套实现;例如,增加一种消息类型,需要实现所有不同的消息发送方式;

这意味着,以后每次扩展一下消息类型或消息方式,都必须要实现这其对应的全套处理方式,是不是很痛苦?

采用通过继承来扩展的实现方式,有个明显的缺点:扩展消息的类型或方式不太容易,很容易会造成类爆炸问题,扩展起来不灵活。

就没有更好的解决方案吗?

3、解决问题 && 桥接模式类图及组成

先来看看桥接模式的类图及组成,解决方案及代码稍后讲解;

(引)类图:

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

组成:

  抽象类(Abstraction):定义抽象类的接口,维护一个指向Implementor类型对象的引用。

  扩充抽象类(RefinedAbstraction):扩充由Abstraction定义的接口。

  实现类接口(Implementor):定义实现类的接口,该接口不一定要与Abstraction的接口完全一致;事实上这两个接口可以完全不同。一般来讲, Implementor接口仅提供基本操作,而 Abstraction则定义了基于这些基本操作的较高层次的操作。

  具体实现类(ConcreteImplementor):实现Implementor接口并定义它的具体实现。

代码结构:

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

/** * 定义实现部分的接口,可以与抽象部分接口的方法不一样 
*/  public interface Implementor {  
  /** 
   * 示例方法,实现抽象部分需要的某些具体功能 
   */  
  public void operationImpl();  
}/** * 定义抽象部分的接口 
*/public abstract class Abstraction {  
  /** 
   * 持有一个实现部分的对象 
   */  
  protected Implementor impl;  
  /** 
   * 构造方法,传入实现部分的对象  
   * @param impl 实现部分的对象 
   */  
  public Abstraction(Implementor impl){  
      this.impl = impl;  
  }  
  /** 
   * 示例操作,实现一定的功能,可能需要转调实现部分的具体实现方法 
   */  
  public void operation() {  
      impl.operationImpl();  
  }  
}/** * 真正的具体实现对象 
*/  public class ConcreteImplementorA implements Implementor {  
  public void operationImpl() {   
      //真正的实现    }  
}  

/** * 真正的具体实现对象 
*/  public class ConcreteImplementorB implements Implementor {  
  public void operationImpl() {   
      //真正的实现    }  
}/** * 扩充由Abstraction定义的接口功能 
*/  public class RefinedAbstraction extends Abstraction {  
  public RefinedAbstraction(Implementor impl) {  
      super(impl);  
  }  
  /** 
   * 示例操作,实现一定的功能 
   */  
  public void otherOperation(){  
      //实现一定的功能,可能会使用具体实现部分的实现方法,  
      //但是本方法更大的可能是使用Abstraction中定义的方法,  
      //通过组合使用Abstraction中定义的方法来完成更多的功能    }  
}

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

 这里大家对桥接模式有点印象没?

接下来,咱们利用桥接模式来解决上述的问题:解决方案:是根据实际需要对消息类型和消息方式进行组合。

示意图如下:

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

下面在维度上看一下组合情况:

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

实现代码:

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

package com.designpattern.bridge.solution_2;/**
 * 实现发送消息的统一接口 
 * @author Json*/ public interface MessageImplementor {  
   /** 
    * 发送消息 
    * @param message 消息内容 
    * @param toUser 接收人 
    */  
    public void send(String message,String users);  
}

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

package com.designpattern.bridge.solution_2;/**
 * 抽象的消息对象
 * @author Json*/public abstract class AbstractMessage {    /** 
     * 持有一个实现部分的对象 
     */  
    protected MessageImplementor impl;  
      
    /** 
     * 构造方法,传入实现部分的对象  
     * @param impl 实现部分的对象 
     */  
    public AbstractMessage(MessageImplementor impl){  
        this.impl = impl;  
    }  
      
    /** 
     * 发送消息,转调实现部分的方法 
     * @param message 消息内容 
     * @param toUser 接收人 
     */  
    public void sendMessage(String message,String toUser){  
        this.impl.send(message, toUser);  
    }     
}

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

 3种消息方式:

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

package com.designpattern.bridge.solution_2;/**
 * 使用站內消息方式发送信息
 * @author Json*/public class SystemMessage implements MessageImplementor {

    @Override    public void send(String message, String users) {
        System.out.println("使用站內消息方式,发送信息【"+message+"】To【"+users+"】");
    }
}

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

package com.designpattern.bridge.solution_2;/**
 * 使用短信方式发送信息
 * @author Json*/public class MobileMessage implements MessageImplementor {

    @Override    public void send(String message, String users) {
        System.out.println("使用短信方式,发送信息【"+message+"】To【"+users+"】");
    }
}

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

package com.designpattern.bridge.solution_2;/**
 * 使用邮件方式发送信息
 * @author Json*/public class EmailMessage implements MessageImplementor {

    @Override    public void send(String message, String users) {
        System.out.println("使用邮件方式,发送信息【"+message+"】To【"+users+"】");
    }
}

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

 3种消息类型:

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

package com.designpattern.bridge.solution_2;/**
 * 扩展抽象的消息  -- 普通消息
 * @author Json*/public class CommonMessage extends AbstractMessage{    public CommonMessage(MessageImplementor impl) {        super(impl);
    }    public void sendMessage(String message, String toUser) {  
        message = "*普通*:" + message;        super.sendMessage(message, toUser);  
    }   
}

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

package com.designpattern.bridge.solution_2;/**
 * 扩展抽象的消息  -- 加急消息
 * @author Json*/public class UrgencyMessage extends AbstractMessage{    public UrgencyMessage(MessageImplementor impl) {        super(impl);
    }    public void sendMessage(String message, String toUser) {  
        message = "*加急*:" + message;        super.sendMessage(message, toUser);  
    }   
}

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

package com.designpattern.bridge.solution_2;/**
 * 扩展抽象的消息  -- 特急消息
 * @author Json*/public class VeryUrgencyMessage extends AbstractMessage{    public VeryUrgencyMessage(MessageImplementor impl) {        super(impl);
    }    
    public void sendMessage(String message, String toUser) {  
        message = "*特急*:" + message;        super.sendMessage(message, toUser);  
    }   
    
    /** 
     * 扩展自己的新功能:特急任务,需要催促接收人尽快完成
     * @param messageId 消息的编号 
     * @return
     */  
    public void urge(String messageId) {  
        //发出催促的信息  ,比如:每隔半小时 发送一条催促消息        //TODO 逻辑    }  
}

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

 测试:

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

package com.designpattern.bridge.solution_2;/**
 * 测试
 * @author Json*/public class Client {

版权声明,转载请注明出处:http://www.cnblogs.com/JsonShare

http://www.cnblogs.com/JsonShare/p/7233342.html