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

  • 相关阅读:
    phonegap_android配置文档
    JQueryMobile + PhoneGap 经验总结
    nand ECC 算法记录
    u-boot 2016.05 添加自己的board 以及config.h
    git commit 多行注释方法说明
    Ubuntu 下新建用户后无法sudo
    QT4.8.5 QComboBox 增加选择菜单记录
    Linux GPIO控制方法
    Qt5 can't find -LGL
    windows 端搭建nfs 服务器
  • 原文地址:https://www.cnblogs.com/wencheng9012/p/13445419.html
Copyright © 2011-2022 走看看