大话设计模式读书笔记(桥接模式)

人物:大鸟,小菜

事件:大鸟玩魂斗罗手机游戏,小菜也想玩,但因为这款手机游戏只能适配大鸟的手机,却不能适配小菜的手机,小菜抱怨说如果游戏软件能够统一适配就好了,大鸟笑着给小菜讲解了桥接模式


桥接模式:

1.阐述了设计程序时紧耦合思路演化

2.为解决紧耦合的缺陷,引出了合成/聚合复用原则

3.由合成/聚合复用原则展开了松耦合实现

紧耦合的程序演化

1.用代码设计:一个N品牌的手机,拥有一个小游戏

游戏类:

@Slf4j
public class HandsetNGame {
    public void runGame() {
        log.info("运行N品牌手机游戏");
    }
}

客户端:

HandsetNGame game = newHandsetNGame();
game.runGame();

2.设计:一个品牌N的手机有一个小游戏,一个品牌M的手机有一个小游戏(因为两个品牌都有游戏,他们都有共同的runGame接口,所以可以抽象个父类出来)

 HandsetGame类,抽象父类:

@Slf4j
public abstract class HandsetGame {
    public abstract void runGame();
}

M类手机和N类手机都继承它:

@Slf4j
public class HandsetMGame extends HandsetGame {
    @Override
    public void runGame() {
        log.info("运行M品牌手机游戏");
    }
}
@Slf4j
public class HandsetNGame extends HandsetGame {
    @Override
    public void runGame() {
        log.info("运行N品牌手机游戏");
    }
}

3.设计:M品牌手机和N品牌手机再加上都有通讯录功能

小菜的结构图:

代码实现如下:

手机品牌:

public class HandsetBrand {
    public void phoneRun() {
    }
}

手机品牌N和手机品牌M:

public class HandsetBrandN extends HandsetBrand {
}
public class HandsetBrandM extends HandsetBrand {
}

手机品牌M的游戏和通讯录:

@Slf4j
public class HandsetBrandMGame extends HandsetBrandM {
    @Override
    public void phoneRun(){
       log.info("运行M品牌手机游戏");
    }
}
@Slf4j
public class HandsetBrandMAddressList extends HandsetBrandM {
    @Override
    public void phoneRun() {
        log.info("运行M品牌手机通讯录");
    }
}

手机品牌N的游戏和通讯录:

@Slf4j
public class HandsetBrandNGame extends HandsetBrandN {
    @Override
    public void phoneRun() {
        log.info("运行N品牌手机游戏");
    }
}
@Slf4j
public class HandsetBrandNAddressList extends HandsetBrandN {
    @Override
    public void phoneRun() {
        log.info("运行N品牌手机通讯录");
    }
}

客户端代码:

public class PhoneCliengt {
    public static void main(String[] args) {
        HandsetBrand ab;

        ab = new HandsetBrandMAddressList();
        ab.phoneRun();

        ab = new HandsetBrandMGame();
        ab.phoneRun();

        ab = new HandsetBrandNAddressList();
        ab.phoneRun();

        ab = new HandsetBrandNGame();
        ab.phoneRun();
    }
}

输出结果:

运行M品牌手机通讯录
运行M品牌手机游戏
运行N品牌手机通讯录
运行N品牌手机游戏

大鸟:如果每个手机增加mp3功能

小菜:再在每个手机下增加一个子类

大鸟:如果再增加一个手机品牌

小菜:那就再增加一个手机品牌和三个子类,现在感觉有点麻烦了

大鸟:如果再增加一个功能,那不是又要增加三个子类么

小菜:那我换一种思路,如下:

小菜思考了下:还是不行,如果要增加一个功能,还是会有很大的影响

合成/聚合复用原则

    尽可能使用合成/聚合,尽量不要使用类继承

    因为对象的继承是在编译时就定义好了,所以运行时无法改变从父类继承的实现,子类和父类有非常紧密的依赖关系,当需要复用子类时,当继承下来的实现不适合解决新的问题,则父类必须重写或被其他合适的类替换,这种依赖关系限制了灵活性,并最终限制了复用性。

1.合成/聚合结构图

2.合成/聚合的好处:优先使用对象的合成/聚合将有助于你保持每个类被封装,并集中在单个任务上。这样的类和类继承层次会保持较小的规模,并且不太可能增长成不可控制的庞然大物。

3.结合上述例子的代码结构图:

小菜:手机品牌包含手机软件,但手机软件不是手机品牌的一部分,所以是聚合关系

松耦合的程序

HandsetSoft类,手机软件:

public abstract class HandsetSoft {
    public abstract void run();
}

HandsetGame类,手机游戏:

@Slf4j
public class HandsetGame extends HandsetSoft {
    @Override
    public void run() {
        log.info("运行手机游戏");
    }
}

HandsetAddressList类,手机通讯录:

@Slf4j
public class HandsetAddressList extends HandsetSoft {
    @Override
    public void run() {
        log.info("运行手机通讯录");
    }
}

HandsetBrand类,手机品牌类:

public abstract class HandsetBrand {
    protected HandsetSoft soft;

//设置手机软件
public void setHandsetSoft(HandsetSoft soft) { this.soft = soft; } public abstract void run(); }

品牌N,品牌M具体类:

public class HandsetBrandN extends HandsetBrand {
    @Override
    public void run() {
        soft.run();
    }
}
public class HandsetBrandM extends HandsetBrand {
    @Override
    public void run() {
        soft.run();
    }
}

客户端调用:

public class PhoneClient {
    public static void main(String[] args) {
        HandsetBrand ab;
        ab = new HandsetBrandN();

        ab.setHandsetSoft(new HandsetGame());
        ab.run();

        ab.setHandsetSoft(new HandsetAddressList());
        ab.run();

        ab = new HandsetBrandM();

        ab.setHandsetSoft(new HandsetGame());
        ab.run();

        ab.setHandsetSoft(new HandsetAddressList());
        ab.run();
    }
}

大鸟:这样如果增加mp3功能,就增加一个类就行,如果增加手机品牌,也只是增加一个类就行,不会影响其他类,这个模式其实叫做桥接模式。桥接模式也就是将抽象部分与它的实现部分分离,使它们都可以独立地变化。

原文地址:https://www.cnblogs.com/wencheng9012/p/13445419.html