经典设计模式——桥接模式

    桥接模式是一种结构型模式,它主要应对的是:由于实际的需要,某个类具有两个或以上维度的变化,如果只是使用继承,将无法实现这种需要,或者是的设计变得更加臃肿。

    举例来说,假设现在我们需要为某个餐厅制造菜单,餐厅供应牛肉面、猪肉面……,而且顾客可以根据自己的口味选择是否添加辣椒。此时就产生了一个问题,我们如何来应对这种变化(这已经是两个维度的变化了,一个维度是面里面加的什么肉,另一个维度是加不加辣椒)?我们是否需要定义辣椒牛肉面、无辣牛肉面、辣椒猪肉面、无辣猪肉面4(2^2)个子类?如果还有一个加不加醋的面呢(这是第三个维度)?那不是要定义8(2^3)个子类?想想如果餐厅还供应羊肉面,酸菜面呢?

    为了解决这个问题,我们可以使用桥接模式,桥接模式的做法是把变化的部分抽象出来,使变化部分与主类(相当于就是桥接类)分离开来,从而将多个维度的变化彻底分离。最后提供一个管理类来组合不同维度上的变化,通过这种组合来满足业务需要。

    下面以一个简单的实例来说明桥接模式的使用。程序先提供了一个Peppery接口,该接口代表是否添加辣椒:

public interface Peppery {
    String style();
}

    接着为该接口提供两个实现类,它们分别表示添加辣椒和不添加辣椒:

public class PepperyStyle implements Peppery {
    @Override
    public String style() {
        System.out.println("辣味十足,爽!");
    }
}

public class PlainStyle implements Peppery {
    @Override
    public String style() {
        System.out.println("清淡一点,养胃");
    }
}

    从上面的接口可以看出,Peppery接口代表了加不加辣椒这个维度的变化,不论面条在该维度上有多少种变化(辣味还可能有微辣、中辣、重辣等),程序只需要为这几种变化分别提供实现类即可。对于系统而言,辣味风格这个维度上的变化是固定的,程序必须面对的 ,程序使用桥接模式将辣味风格这个维度的变化抽象出来,避免了与牛肉、猪肉、羊肉等材料这个维度的变化耦合在一起。

    接着程序提供了一个AbstractNoodle抽象类,该抽象类将会持有一个Peppery属性,该属性代表面条的辣味风格。程序通过AbstractNoodle组合一个Peppery对象,从而实现了面条在辣味风格这个维度上的变化,而AbstractNoodle本身可以包含很多实现类,不同实现类则代表了面条在不同材料风格这个维度的变化。下面是AbstractNoodle的代码:

public abstract class AbstractNoodle {
    protected Peppery style;
    public AbstractNoodle(Peppery style) {
        this.style = style;
    }
    public abstract void eat();
}

    正如上面的代码所示,AbstractNoodle类中持有一个Peppery类型的实例,不同的AbstractNoodle实例与不同的Pepper实例组合,就可以完成辣味风格、材料风格两个维度的变化(这里只简单说明这两个维度的变化,更多维度,原理相同)。由此可见,AbstractNoodle抽象类可以看作是一个桥梁,它被用来“桥接”面条的材料风格的改变与辣味风格的改变,是面条的特殊属性得到无绑定的扩充。

    接下类为AbstractNoodle提供一个子类PorkyNoodle,该类代表了“猪肉面”:

public class PorkyNoodle extends AbstractNoodle {
    public PorkyNoodle(Peppery style) {
        super(style)
    }
    @Override
    public void eat() {
        System.out.println("这是一碗猪肉面,辣味风格为:" + super.style.style());
    }
}

    再提供一个BeefNoodle,该子类代表了“牛肉面”:

public class BeefNoodle extends AbstractNoodle {
    public BeefNoodle(Peppery style) {
        super(style)
    }
    @Override
    public void eat() {
        System.out.println("这是一碗牛肉面,辣味风格为:" + super.style.style());
    }
}

    从PorkyNoodle和BeefNoodle中可以看出,AbstractNoodle的两个具体类实现eat()方法时,既组合了材料风格的变化,也组合了辣味风格的变化,从而可以表现出两个维度的变化。桥接模式下,这些接口和类之间的结构关系如下:

213809_3Btl_1434710.jpg

    下面提供一个主程序,可以分别产生辣椒牛肉面、无辣牛肉面、辣椒猪肉面、无辣猪肉面等几种风格的面条:

public class Test {
    public static void main(String args[]) {
        //辣椒牛肉面
        AbstractNoodle noodle1 = new BeefNoodle(new PepperyStyle());
        //无辣牛肉面
        AbstractNoodle noodle2 = new BeefNoodle(new PlainStyle());
        //辣椒猪肉面
        AbstractNoodle noodle3 = new PorkyNoodle(new PepperyStyle());
        //无辣猪肉面
        AbstractNoodle noodle4 = new PorkyNoodle(new PlainStyle());
        
        noodle1.eat();
        noodle2.eat();
        noodle3.eat();
        noodle4.eat();
    }
}

    上面的main方法中得到了这4中面条,这4种面条满足了面条在两个维度上的变化,而程序结构又足够清晰且扩展性好。

    桥接模式在JavaEE架构中有非常广泛的用途,由于JavaEE应用需要实现跨数据库的功能,程序为了在不同数据库之间迁移,因此系统需要在持久化技术这个维度上存在改变;除此之外,系统也需要在不同业务逻辑实现之间迁移,因此也需要在逻辑实现这个维度存在改变,这正好符合桥接模式的使用场景。因此,JavaEE应用都会推荐使用业务逻辑组件和DAO组件分离的结构,让DAO组件负责持久化技术这个维度上的改变,让业务逻辑组件负责业务逻辑实现这个维度上的改变。由此可见,JavaEE应用中常见的DAO模式正是桥接模式的应用。


转载于:https://my.oschina.net/itblog/blog/215221

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值