zoukankan      html  css  js  c++  java
  • 大话设计模式读书笔记(桥接模式)

    人物:大鸟,小菜

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


    桥接模式:

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

  • 相关阅读:
    遗传算法(Genetic Algorithm, GA)及MATLAB实现
    CCF CSP 201809-2 买菜
    PAT (Basic Level) Practice (中文)1008 数组元素循环右移问题 (20 分)
    PAT (Basic Level) Practice (中文)1006 换个格式输出整数 (15 分)
    PAT (Basic Level) Practice (中文)1004 成绩排名 (20 分)
    PAT (Basic Level) Practice (中文)1002 写出这个数 (20 分)
    PAT (Advanced Level) Practice 1001 A+B Format (20 分)
    BP神经网络(原理及MATLAB实现)
    问题 1676: 算法2-8~2-11:链表的基本操作
    问题 1744: 畅通工程 (并查集)
  • 原文地址:https://www.cnblogs.com/wencheng9012/p/13445419.html
Copyright © 2011-2022 走看看