Bridge模式学习笔记

来源:互联网 发布:淘宝店铺违规怎么处罚 编辑:程序博客网 时间:2024/05/15 23:08

 1.定义 

1:将抽象和行为相分离,各自可以独立变化,通过动态的结合实现解耦板桥里人).从对象的构成来定义,一般我们定义对象是属性和行为的组合。 

2:将抽象和抽象方法的实现相分离,各自可以独立变化,通过动态的结合实现解耦(GOF).从对象方法角度来定义。比如说通过JDBC访问数据库,我们操作的API是基于接口的,是抽象,没有实现。而特定数据库提供的驱动测试抽象方法的具体实现。

2.Bridge模式的结构图

 


3.设计中面临的问题 

咖啡杯有大有小,咖啡本身可以加牛奶,也可以不加。因此针对以上需求设计如下4个类,中杯加奶、大杯加奶、中杯不加奶、大杯不加奶。层次结构如下。

 

但是,我们注意到:上面四个子类中有概念重叠,可从另外一个角度进行考虑,这四个类实际是两个角色的组合:抽象和行为,其中抽象为:中杯和大杯;行为为:加奶 不加奶(如加橙汁 加苹果汁). 

实现四个子类在抽象和行为之间发生了固定的绑定关系,如果以后加葡萄汁的行为,就必须再增加两个类:中杯加葡萄汁和大杯加葡萄汁。如果客户需要添加小杯产品则需要添加2(加或不加)*2(奶,葡萄汁)种类。类的种类会成指数增长,这样扩展性极差,不易维护。 

行文至此,突然发现变化的部分其实是添加的饮品。杯子的大小也是可以变化的,但相对与可添加的饮品来说变化要小的多。若以加或不加作为设计不变,因为所有的不加其实都是一样的。设计如下

 

同样是11个类,但如果要添加苹果汁第一种则需要额外4个类,第二张则只需要添加2个类。这样同样会带来子类无限增长的噩梦,不容易维护。

4.解决问题 

那我们从分离抽象和行为的角度,使用Bridge模式来实现。 

先看看抽象部分的接口代码:

public abstract class Coffee {

 

    private CoffeeAdditive coffeeImp;

 

    public void setCoffeeImp(CoffeeAdditive coffeeImp) {

        this.coffeeImp = coffeeImp;

    }

 

    public CoffeeAdditive getCoffeeImp() {

        return this.coffeeImp;

    }

 

    public abstract void pourCoffee();

 

}

其中CoffeeImp是加不加奶的行为接口,看其代码如下:

public abstract class CoffeeImp {

    public abstract void pourCoffeeImp();

}

现在我们有了两个抽象类,下面我们分别对其进行继承,实现concrete class: 

中杯

public class MediumCoffee extends Coffee{

    public void pourCoffee() {

        // 我们以重复次数来说明是冲中杯还是大杯 ,重复2次是中杯

        for (int i = 0; i < 2; i++) {

            this.getCoffeeImp().pourCoffeeImp();

        }

}

}

大杯

public class SuperSizeCoffee extends Coffee{

    @Override

    public void pourCoffee() {

        // 我们以重复次数来说明是冲中杯还是大杯 ,重复3次是大杯

        for (int i = 0; i < 3; i++) {

            this.getCoffeeImp().pourCoffeeImp();

        }

    }

}

加奶

public class MilkCoffeeImp extends CoffeeImp {

    @Override

    public void pourCoffeeImp() {

        System.out.println("加了美味的牛奶");

    }

}

什么都不加

public class OnlyCoffeeImp extends CoffeeImp {

    @Override

    public void pourCoffeeImp() {

        System.out.println("什么都没加,清香");

    }

}

加葡萄汁

public class GrapeJuiceCoffee extends CoffeeImp {

    @Override

    public void pourCoffeeImp() {

        System.out.println("加葡萄汁,爽口");

}

}

下面示例展示了如何组合一中杯加牛奶的咖啡。

public class Main {

    public static void main(String[] args) {

        Coffee coffee = new MediumCoffee();

        coffee.setCoffeeImp(new MilkCoffeeImp());

        coffee.pourCoffee();

    }

}

这样就很容易添加新的饮品或者是杯子的种类,通过组合使双方解耦,达到易维护易扩展的目的。

更新后的代码结构如下(菱形应该是空心的,Visio竟然不支持。)

 

5.Bridge模式在JDBC中的应用 

看到很多关于设计模式的书籍中都提到JDBC使用了Bridge设计模式,下面基于JDK源代码做个简单的分析。众所周知,JDBC只是Sun的技术标准,说白了就是一套API,真正起作用的是各家数据的产商提供的驱动。数据库连接是一个抽象的行为,而起具体的实现是有外部的驱动实现的。符合Bridge模式所解决的问题特质。 

在使用JDBC的过程中我们主要是跟DriverManager打交道。注册驱动和获取连接。对应Bridge模式的结构图,DriverManagerAbstraction,没有RefinedAbstraction。而java.sql.Driver对应Impementor,各种类型的数据库驱动则是ConcreteImpementor 

连接数据库的第一个步骤就是加载驱动,然后就是获得数据库连接。也就是说在第一步之后系统已经知道客户使用的数据库类型了。通常大家都是用Class.forName一下数据库驱动,也可以创建一个驱动类的实例然后注册到DriverManager里面。以Oracle数据库驱动为例,看下面代码片段(移除部分代码)。

    static

    {

        defaultDriver = null;

        if(defaultDriver == null)

        {

             defaultDriver = new OracleDriver();

             DriverManager.registerDriver(defaultDriver);

        }

    }

Static方法块在类被加载之后就会执行,也就是说Oracle驱动实际上创建了一个新的实例并注册到DriverManager里面。因此建议使用第一种方式,避免重复调用。 

通过加装Oracle数据库驱动把具体的实现组合到DriverManager里面,然后DriverManager会遍历所有注册的驱动并尝试创建连接,然后返回第一个创建成功的数据库连接。

6.总结
1.做对象分析的时候使用共性/可变分析比使用名词/动词更有效。
2.找出系统中变化部分并且将其封装。
3.优先使用对象聚集,而不是继承。

日期:2009-9-9

参考网站:http://www.jdon.com/designpatterns/bridge.htm

参考书籍:《Design Pattern in Java

                    《Design Pattern Explained》

附件:Bridge模式类图

      第一种设计类图

      第二种设计类图

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 企业被列入经营税务异常名录怎么办 手机号被别人绑定了企业微信怎么办 刚出生一天的婴儿不肯吃奶怎么办 9个月孩子不好好吃奶怎么办 孩子2个月吃奶老是呛到怎么办 孩子4个月不好好吃奶怎么办? 3个月的孩子不吃奶肚子胀怎么办 刚出生的婴儿吃完奶打嗝怎么办 宝宝刚生下来一直睡觉不吃奶怎么办 刚生下来的婴儿不吃奶怎么办 刚生下来的小猫不吃奶怎么办 刚生的小羊羔不吃奶怎么办 刚出生的婴儿不会吸奶怎么办 生完小孩七十天妈妈咳嗽怎么办 带欣的名字三个字儿的怎么办 二十多岁的儿子沉迷游戏网络怎么办 为什么打开游戏网络却用不了怎么办 打来微信网页版显示证书错误怎么办 开了家定制家具店生意不好怎么办 宝宝起风疹怎么办要注意的问题 超市买的内裤西铁牌子没去掉怎么办 没申请生产许可证贴标了怎么办 淘宝没有品牌非要我写品牌怎么办没 意外怀孕明明一直用安全套的怎么办 找不到百度网盘的dns地址怎么办 小米众筹到了发货时间不发货怎么办 不知道电脑宽带连接账号密码怎么办 电脑如果宽带账号密码忘记了怎么办 xp电脑用户名和密码忘了怎么办 电脑的用户名和密码忘记了怎么办 电脑重置后需要用户名和密码怎么办 电脑登录用户名和密码忘记了怎么办 电脑登录用户名和密码忘了怎么办啊 微信无意中点了允许登录怎么办 qq号码登录微信无法验证怎么办 注册微信公众号邮箱激活不了怎么办 不是自己申请的qq号忘密码怎么办 联通宽带拨号账号密码忘记了怎么办 忘了路由器的用户名和密码怎么办 宽带连接用户名和密码忘了怎么办 江西银行网银用户名忘记了怎么办