zoukankan      html  css  js  c++  java
  • 一天一个设计模式——Bridge桥接模式

    一、概念准备

      在理解桥接模式之前,先要理解面向对象程序设计中的两个概念:

    • 类的功能层次结构:假设现在有一个类Something,这个类有一些成员属性和成员方法,但是现有的功能不能满足要求,因此我们想扩展这个类,给这个类创建一个子类SomethingBetter来继承它,并在子类中添加更多属性和方法。像这样不同的功能位于不同的类继承结构中,就构成了类的功能层次结构。
    • 类的实现层次结构:回顾一下抽象类的作用,抽象类声明抽象方法(定义了方法接口API),然后在继承它的子类中实现相关方法。由于我们将方法定义和实现分离到了不同的类中,从而实现了类的高可替换性,并有了模板Template Method方法模式。虽然这里也有父类和子类的继承关系,但是这里的继承并不是为了增加新功能,而是为了完成“定义——实现 分离”中的实现环节。这种层次结构就是类的实现层次接口。

    二、模式说明

      如果类的设计都只有一层(程序中自定义的类不存在继承关系),这时候类的功能层次结构和实现层次结构是混杂在一起的,也很难扩展(无法确定应该继承哪个类来扩展功能,同一个方法如果想替换其实现也无法做到)。因此需要按照上面说的,将类的功能层次和实现层次分开,为了在分开后能继续保持一定的联系,这时候就需要一个桥梁,将它们连接起来。(Bridge也有桥梁的意思,连接两个事物)

    三、代码示例

      在下面的桥接模式代码示例中,着重关注哪些时功能层次,哪些是实现层次,二者又是如何桥接起来的。

    1、类的功能层次结构

    Display类:Display类的功能是抽象的,负责“显示”一些东西,它位于功能层次结构的最上层。open、print、close这三个方法是Display类提供的接口,它们定义了显示的步骤,这三个方法调用的是Display实现类的对象。

    package com.designpattern.cn.bridgepattern;
    
    public class Display {
        private DisplayImpl impl;
        public Display(DisplayImpl impl){
            this.impl = impl;
        }
        public void open(){
            impl.rawOpen();
        }
        public void print(){
            impl.rawPrint();
        }
        public void close(){
            impl.rawClose();
        }
        public final void display(){
            open();
            print();
            close();
        }
    }
    View Code

    CountDisplay类:CountDisplay类在Display类的基础上增加了一个新功能,具有“只显示规定次数”的功能。因此,这属于“类的功能层次范畴”。

    package com.designpattern.cn.bridgepattern;
    
    public class CountDisplay extends Display {
        public CountDisplay(DisplayImpl impl){
            super(impl);
        }
        public void multiDisplay(int times){
            open();
            for(int i=0; i < times; i++){
                print();
            }
            close();
        }
    }
    View Code

    2、类的实现层次结构

    DisplayImpl类:位于“类的实现层次结构”的最上层。DisplayImpl是抽象类,声明了rawOpen、rawPrint、rawClose三个抽象方法。

    package com.designpattern.cn.bridgepattern;
    
    public abstract class DisplayImpl {
        public abstract void rawOpen();
        public abstract void rawPrint();
        public abstract void rawClose();
    }
    View Code

    StringDisplayImpl类:它是仙子字符串的类,但它并不是直接显示字符串,而是继承了DisplayImpl类,作为子类来使用rawOpen、rawPrint、rawClose三个方法显示字符串。

    package com.designpattern.cn.bridgepattern;
    
    public class StringDisplayImpl extends DisplayImpl {
        private String string;
        private int width;
        public StringDisplayImpl(String string){
            this.string = string;
            this.width = string.getBytes().length;
        }
        @Override
        public void rawOpen(){
            printLine();
        }
        @Override
        public void rawPrint(){
            System.out.println("|" + string + "|");
        }
        @Override
        public void rawClose() {
            printLine();
        }
    
        private void printLine(){
            System.out.print("+");
            for(int i = 0; i < width; i++){
                System.out.println("-");
            }
            System.out.println("+");
        }
    }
    View Code

    3、Main类测试结果

    四、模式类图

    五、模式中的角色

    • Abstraction抽象化:类的功能层次的最上层,它使用Implementor角色的方法定义了基本功能,如上面的Display类。
    • RefinedAbstraction改善后的抽象化:增加了Abstraction的功能,如上面的CountDisplay类。
    • Implementor实现者:类的实现层次结构最上层,定义了用于实现Abstraction的角色的接口方法,如上面的DisplayImpl类。
    • ConcreteImplementor具体实现者:负责实现Implementor角色定义的接口方法,如上面的StringDisplayImpl类。

    那么,这其中的桥梁Bridge是什么呢?对于示例程序,Display类和DisplayImpl是如何关联的,从程序中看出,这里的桥梁应该是impl字段。

    六、相关的设计模式

    • 模板方法Template Method模式:模板方法模式就是使用了桥接模式中的类的实现层次结构。父类调用抽象方法,子类实现具体方法。
    • 抽象工厂Abstract Factory模式:可以使用抽象工厂设计出更好的ConcreteImplementor类。
    • 适配器Adapter模式:桥接模式连接了类的结构层次和实现层次,适配器模式则将功能类似,但是接口不匹配的类结合在一起。

    七、扩展

    • 采用bridge桥接模式分离功能层次和实现层次,更有利于类的扩展,如果要增加功能,只需在功能层次这一侧做修改,无需调整实现层次,并且所有的实现层次都能利用增加的功能。
    • 继承是强关联,委托是弱关联。继承可以方便的得到功能更强的类,但是一旦使用继承,则在类之间形成了强关联关系,如果想改变或者替换其中的一个类,就必须修改类的代码。上面的例子中,使用了委托,只有当Display类的实例生成时,才作为参数,与被传入的类构成关联关系(示例程序中,只有Main类生成Display类和CountDisplay类的实例时,才将StringDisplayImpl类的实例作为参数传递给Display类和CountDisplay类)。除了StringDisplayImpl类,我们可以使用任意一个ConcreteImplementor角色传递给Display类和CountDisplay类,就能很容易的改变实现(只需修改Main类,Display类和DisplayImpl无需任何修改)。
  • 相关阅读:
    10个用jQuery实现图片幻灯片/画廊效果和源码
    老赵面试题参考答案(二)
    C#的显式接口和隐式接口
    老赵面试题参考答案(三)
    C#中的参数传递:值类型(value type)和引用类型(reference type)
    word转换成html的方法
    老赵面试题参考答案(四)
    五个Metro UI 风格的网页设计
    老赵面试题参考答案(六)
    概要设计怎么写?
  • 原文地址:https://www.cnblogs.com/zheng-hong-bo/p/11106278.html
Copyright © 2011-2022 走看看