手机软件何时统一--桥接模式

news2024/11/28 14:42:19

1.1 凭什么你的游戏我不能玩

2007年苹果手机尚未出世,机操作系统多种多样(黑莓、塞班、Tizen等),互相封闭。而如今,存世的手机操作系统只剩下苹果OS和安卓,鸿蒙正在稳步进场。

1.2 紧耦合的程序演化

手机硬件软件和PC硬件软件,现在有一个N品牌的手机,它有一个小游戏,M品牌的手机,它有一个小游戏.

代码结构图

package code.chapter22.bridge1;

public class Test {

    public static void main(String[] args) {

        System.out.println("**********************************************");       
        System.out.println("《大话设计模式》代码样例");
        System.out.println();       

        HandsetBrandNGame game=new HandsetBrandNGame();
        game.run();

        HandsetGame game2 = new HandsetBrandMGame();
        game2.run();

        System.out.println();
        System.out.println("**********************************************");
    }
}

// //手机品牌N的游戏
// class HandsetBrandNGame {
//     public void run(){
//         System.out.println("运行N品牌手机游戏");
//     }
// }

//手机游戏类
class HandsetGame{
    public void run(){
    }
}

//手机品牌M的游戏
class HandsetBrandMGame extends HandsetGame{
    public void run(){
        System.out.println("运行M品牌手机游戏");
    }
}
//手机品牌N的游戏
class HandsetBrandNGame extends HandsetGame{
    public void run(){
        System.out.println("运行N品牌手机游戏");
    }
}

如果我现在需要每个品牌都增加一个音乐播放功能,那就在每个品牌的下面增加一个子类。现在又来了一家新的手机品牌S,它也有游戏、通讯录、音乐播放器,那就增加手机品牌S类和三个下属功能子类,如果我需要增加“”输入法”功能、拍照功能,再增加L品牌X品牌呢?

上面好像也解决不了问题。

        "是呀,就像我刚开始学会用面向对象的继承时,感觉它既新颖又功能强大,所以只要可以用,就都用上继承。这就好比是'有了新锤子,所有的东西看上去都成了钉子。[DPE]'但事实上,很多情况用继承会带来麻烦。比如,对象的继承关系是在编译时就定义好了,所以无法在运行时改变从父类继承的实现。子类的实现与它的父类有非常紧密的依赖关系,以至于父类实现中的任何变化必然会导致子类发生变化。当你需要复用子类时,如果继承下来的实现不适合解决新的问题,则父类必须重写或被其他更适合的类替换。这种依赖关系限制了灵活性并最终限制了复用性[DP]。"
        "是呀,我这样的继承结构,如果不断地增加新品牌或新功能,类会越来越多的。"
        "在面向对象设计中,我们还有一个很重要的设计原则,那就是合成/聚合复用原则。即优先使用对象合成/聚合,而不是类继承[DP]。

1.3 合成/聚合复用原则

        合成/聚合复用原则(CARP),尽量使用合成/聚合,尽量不要使用类继承。[J&DP]
        合成(Composition,也有翻译成组合)和聚合(Aggregation)都是关联的特殊种类。
        聚合表示一种弱的'拥有'关系,体现的是A对象可以包含B对象,但B对象不是A对象的一部分;合成则是一种强的'拥有'关系,体现了严格的部分和整体的关系,部分和整体的生命周期一样[DPE]。比方说,大雁有两个翅膀,翅膀与大雁是部分和整体的关系,并且它们的生命周期是相同的,于是大雁和翅膀就是合成关系。而大雁是群居动物,所以每只大雁都是属于一个雁群,一个雁群可以有多只大雁,所以大雁和雁群是聚合关系。"


        "合成/聚合复用原则的好处是,优先使用对象的合成/聚合将有助于你保持每个类被封装,并被集中在单个任务上。这样类和类继承层次会保持较小规模,并且不太可能增长为不可控制的庞然大物[DP]。就刚才的例子,你需要学会用对象的职责,而不是结构来考虑问题。其实答案就在之前我们聊到的手机与电脑的差别上。"
        "哦,我想想看,手机是不同的品牌公司,各自做自己的软件,就像我现在的设计一样,而PC却是硬件厂商做硬件,软件厂商做软件,组合起来才是可以用的机器。你是这个意思吗?"
        "很好,我很喜欢你提到的'组合'这个词,实际上,像'游戏''通讯录''MP3音乐播放'这些功能都是软件,如果我们可以让其分离与手机的耦合,那么就可以大大减少面对新需求时改动过大的不合理情况。"
        "好的好的,我想想怎么弄,你的意思其实就是应该有个'手机品牌'抽象类和'手机软件'抽象类,让不同的品牌和功能都分别继承于它们,这样要增加新的品牌或新的功能都不用影响其他类了。"
结构图


        "还剩个问题,手机品牌和手机软件之间的关系呢?
        "我觉得应该是手机品牌包含手机软件,但软件并不是品牌的一部分,所以它们之间是聚合关系。"
结构图

1.4 松耦合的程序

package code.chapter22.bridge2;

public class Test {

    public static void main(String[] args) {

        System.out.println("**********************************************");       
        System.out.println("《大话设计模式》代码样例");
        System.out.println();       

        HandsetBrand ab;
        ab = new HandsetBrandMAddressList();
        ab.run();

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

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

        ab = new HandsetBrandNGame();
        ab.run();

        System.out.println();
        System.out.println("**********************************************");
    }
}

//手机品牌
class HandsetBrand{
    public void run(){
    }
}

//手机品牌M
class HandsetBrandM extends HandsetBrand{

}
//手机品牌N
class HandsetBrandN extends HandsetBrand{

}

//手机品牌M的游戏
class HandsetBrandMGame extends HandsetBrandM{
    public void run(){
        System.out.println("运行M品牌手机游戏");
    }
}
//手机品牌N的游戏
class HandsetBrandNGame extends HandsetBrandN{
    public void run(){
        System.out.println("运行N品牌手机游戏");
    }
}

//手机品牌M的通讯录
class HandsetBrandMAddressList extends HandsetBrandM{
    public void run(){
        System.out.println("运行M品牌手机通讯录");
    }
}
//手机品牌N的通讯录
class HandsetBrandNAddressList extends HandsetBrandN{
    public void run(){
        System.out.println("运行N品牌手机通讯录");
    }
}

        "是呀,现在如果要增加一个功能,比如手机音乐播放功能,那么只要增加这个类就行了。不会影响其他任何类。类的个数增加也只是一个。"
        "如果是要增加S品牌,只需要增加一个品牌子类就可以了。个数也是一个,不会影响其他类的改动。"

package code.chapter22.bridge3;

public class Test {

    public static void main(String[] args) {

        System.out.println("**********************************************");       
        System.out.println("《大话设计模式》代码样例");
        System.out.println();       

        HandsetBrand ab;
        ab = new HandsetBrandM();

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

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

        HandsetBrand ab2;
        ab2 = new HandsetBrandN();

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

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

        //向扩展开放,增加的功能
        HandsetBrand ab3;
        ab3 = new HandsetBrandS();
        
        ab3.setHandsetSoft(new HandsetMusicPlay());
        ab3.run();


        System.out.println();
        System.out.println("**********************************************");
    }
}

//手机软件
abstract class HandsetSoft{
    //运行
    public abstract void run();
}

//手机游戏
class HandsetGame extends HandsetSoft{
    public void run(){
        System.out.println("手机游戏");
    }
}

//手机通讯录
class HandsetAddressList extends HandsetSoft{
    public void run(){
        System.out.println("通讯录");
    }
}

//手机品牌
abstract class HandsetBrand{
    protected HandsetSoft soft;

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

    //运行
    public abstract void run();
}

//手机品牌M
class HandsetBrandM extends HandsetBrand{
    public void run(){
        System.out.print("品牌M");
        soft.run();
    }
}
//手机品牌N
class HandsetBrandN extends HandsetBrand{
    public void run(){
        System.out.print("品牌N");
        soft.run();
    }
}

//手机音乐播放
class HandsetMusicPlay extends HandsetSoft{
    public void run(){
        System.out.print("音乐播放");
    }
}

//手机品牌S
class HandsetBrandS extends HandsetBrand{
    public void run(){
        System.out.print("品牌S");
        soft.run();
    }
}



        "这显然也符合了我们之前的一个什么设计原则?"
        "开放-封闭原则。这样的设计显然不会修改原来的代码,而只是扩展类就行了。但今天我感受最深的是合成/聚合复用原则,也就是优先使用对象的合成或聚合,而不是类继承。聚合的魅力无限呀。相比,继承的确很容易造成不必要的麻烦。"
        "盲目使用继承当然就会造成麻烦,而其本质原因主要是什么?"
        "我想应该是,继承是一种强耦合的结构。父类变,子类就必须要变。"
        "OK,所以我们在用继承时,一定要在是'is-a'的关系时再考虑使用,而不是任何时候都去使用。"

        "哈,当然,你看看刚才画的那幅图,两个抽象类之间有什么?像什么?"
        "有一个聚合线,哈,像一座桥。"
        "好,说得好,这个设计模式就叫作'桥接模式'。"

1.5 桥接模式

        桥接模式(Bridge),将抽象部分与它的实现部分分离,使它们都可以独立地变化。[DP]
        "这里需要理解一下,什么叫抽象与它的实现分离,这并不是说,让抽象类与其派生类分离,因为这没有任何意义。实现指的是抽象类和它的派生类用来实现自己的对象[DPE]。就刚才的例子而言,就是让'手机'既可以按照品牌来分类,也可以按照功能来分类。"
按品牌分类实现结构图


按软件分类实现结构图


        "由于实现方式有多种,桥接模式的核心意图是把这些实现独立出来,让它们各自变化。这就使得每种实现的变化不会影响其他实现,从而达到应对变化的目的。"

1.6 桥接模式基本代码

桥接模式(Bridge)结构图

package code.chapter22.bridge0;

public class Test {

    public static void main(String[] args) {

        System.out.println("**********************************************");       
        System.out.println("《大话设计模式》代码样例");
        System.out.println();       

        Abstraction ab;
        ab = new RefinedAbstraction();

        ab.setImplementor(new ConcreteImplementorA());
        ab.operation();

        ab.setImplementor(new ConcreteImplementorB());
        ab.operation();

        System.out.println();
        System.out.println("**********************************************");
    }
}

abstract class Implementor{
    public abstract void operation();
}


class ConcreteImplementorA extends Implementor{
    public void operation(){
        System.out.println("具体实现A的方法执行");
    }
}

class ConcreteImplementorB extends Implementor{
    public void operation(){
        System.out.println("具体实现B的方法执行");
    }
}


abstract class Abstraction{
    protected Implementor implementor;

    public void setImplementor(Implementor implementor){
        this.implementor = implementor;
    }

    public abstract void operation();
}

class RefinedAbstraction extends Abstraction{
    public void operation(){
        System.out.print("具体的Abstraction");
        implementor.operation();
    }
}




Implementor类:
ConcreteImplementorA和ConcreteImplementorB等派生类:Abstraction类:
RefinedAbstraction类:

        "我觉得桥接模式所说的'将抽象部分与它的实现部分分离',还是不好理解,我的理解就是实现系统可能有多角度分类,每一种分类都有可能变化,那么就把这种多角度分离出来让它们独立变化,减少它们之间的耦合。"也就是说,在发现我们需要多角度去分类实现对象,而只用继承会造成大量的类增加,不能满足开放-封闭原则时,就应该要考虑用桥接模式了。

1.7 我要开发“好”游戏

        我要是有钱,就一定去买那种有操作系统,把软件与手机分离的智能手机,说不定我还可以自己开发手机游戏呢。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1577738.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Social Skill Training with Large Language Models

Social Skill Training with Large Language Models 关键字:社交技能训练、大型语言模型、人工智能伙伴、人工智能导师、跨学科创新 摘要 本文探讨了如何利用大型语言模型(LLMs)进行社交技能训练。社交技能如冲突解决对于有效沟通和在工作和…

九泰智库 | 医械周刊- Vol.20

⚖️ 法规动态 国家药监局发布进一步加强医疗器械注册人委托生产监督管理的公告 4月3日,为全面落实医疗器械注册人质量安全主体责任,进一步加强注册人委托生产监督管理,有效防控医疗器械质量安全风险。国家药监局发布关于进一步加强医疗器械…

03-JAVA设计模式-适配器模式

适配器模式 设么是适配器模式 它属于结构型模式,主要用于将一个类的接口转换成客户端所期望的另一种接口,从而使得原本由于接口不兼容而无法协同工作的类能够一起工作。 适配器模式主要解决的是不兼容接口的问题。在软件开发中,经常会有这…

【JavaEE框架】spring之配置数据源和JdbcTemplate

目录 一、数据准备 1、在pom.xml种导入依赖包 2、 建立数据库表 二、测试数据源&#xff08;操作数据库&#xff09; 三、在spring中使用数据源 四、增删改查操作数据库 五、测试 六、部分代码具体分析 一、数据准备 1、在pom.xml种导入依赖包 <dependency><g…

Java设计模式:外观模式之优雅门面(九)

码到三十五 &#xff1a; 个人主页 心中有诗画&#xff0c;指尖舞代码&#xff0c;目光览世界&#xff0c;步履越千山&#xff0c;人间尽值得 ! 在软件工程中&#xff0c;设计模式是解决常见设计问题的经验总结&#xff0c;它为开发者提供了一种通用的、可复用的解决方案。外…

同样是测痛仪有什么不一样?大小鼠足底光热刺痛仪VS大小鼠鼠尾测痛仪

简单介绍&#xff1a; ZL-024E大小鼠足底光热刺痛仪是应用在痛觉生理学、药理学等痛觉研究的仪器。可自动测定大/小鼠在自由状态下足底光热刺激痛阈时间&#xff0c;操作简便&#xff0c;并且可自动得出测定结果&#xff0c;是用于药理实验中研究镇痛**的理想实验仪器。 详情…

编程网站推荐

这里是我的一些喜欢用的编程可以用到的网站 json在线格式化校验工具 随机密码生成

关于近期上架过包的一些总结分享

近期过包包体很多&#xff0c;所以遇到的一些问题也是很多很杂&#xff0c;但是基本上都解决了。少部分因为政策原因导致的包体问题封号&#xff0c;这类就只能先排查问题&#xff0c;再重新制作了。对于拒审问题的解决&#xff0c;希望各位开发者能留下相关流程截图&#xff0…

使用nodejs搭建脚手架工具并发布到npm中

使用nodejs搭建脚手架工具并发布到npm中 一、安装环境依赖及脚手架搭建过程二、搭建Monorepo 风格的脚手架工程三、脚手架的必备模块命令参数模块获取命令参数设置子命令用户交互模块文件拷贝模块脚手架中的路径处理目录守卫文件拷贝模块动态文件生成模块mustache简介自动安装依…

Java 开发篇+一个简单的数据库管理系统ZDB

说明&#xff1a;本文供数据库爱好者和初级开发人员学习使用 标签&#xff1a;数据库管理系统、RDBMS、Java小程序、Java、Java程序 系统&#xff1a;Windows 11 x86 CPU &#xff1a;Intel IDE &#xff1a;IntelliJ IDEA Community Edition 2024 语言&#xff1a;Java语言 标…

在线JSON工具

功能支持 ctrls json格式化游览器本地保存ctrla ctrlc 自动检测选中范围是否是全选&#xff0c;然后按照格式化方式添加到粘贴板中json 粘贴JSON自动格式化json可视化修改json压缩复制json层级折叠json关键key 搜索(自动提示高亮)满足某些近视的可以自行调整字体大小, 并且会游…

React复习全攻略:重温旧知,收获新知

简介 大背景&#xff1a; 起源于 Facebook 的内部项目&#xff0c;因为对市面上所有JS MVC框架不满意&#xff0c;就自己开发了一套&#xff0c;用来开发Instagram项目。&#xff08;开源时间&#xff1a;2013年5月&#xff09; 三句话解释&#xff1a; 是用于构建 Web 和原…

MWeb Pro For Mac v4.5.9 强大的 Markdown 软件中文版

MWeb 是专业的 Markdown 写作、记笔记、静态博客生成软件&#xff0c;目前已支持 Mac&#xff0c;iPad 和 iPhone。MWeb 有以下特色&#xff1a; 软件下载&#xff1a;MWeb Pro For Mac v4.5.9 软件本身&#xff1a; 使用原生的 macOS 技术打造&#xff0c;追求与系统的完美结合…

OpenImageDebugger - CLion研究

在windows下有vistual studio&#xff0c;针对opencv有image watch&#xff0c;在ubuntu下用Clion插件Image Watch要收费&#xff0c;遂研究OpenImageDebugger与CLion问题&#xff0c;还有些未研究透彻&#xff0c;先记录当前部分。 Open Image Debugger Open Image Debugger …

Linux文件IO(4):目录操作和文件属性获取

目录 1. 前言 2. 函数介绍 2.1 访问目录 – opendir 2.2 访问目录 – readdir 2.3 访问目录 – closedir 2.4 修改文件访问权限 – chmod/fchmod 2.5 获取文件属性 – stat/lstat/fstat 2.5.1 文件属性 – struct stat 2.6 文件类型 – st_mode 3. 代码练习 3.1 要求 3.2 代…

深度挖掘商品信息,jd.item_get API助您呈现商品全面规格参数

深度挖掘商品信息&#xff0c;特别是在电商平台上&#xff0c;对于商家、开发者和用户来说都至关重要。jd.item_get API作为京东开放平台提供的一个强大工具&#xff0c;能够帮助用户轻松获取商品的全面规格参数&#xff0c;进而为商品分析、推荐、比较等提供有力的数据支撑。 …

灵猫论文靠谱不 #职场发展#职场发展

对于许多学生和研究人员来说&#xff0c;写论文是一个耗时且具有挑战性的任务。在撰写论文的过程中&#xff0c;除了要进行繁琐的写作工作外&#xff0c;还需要花费大量时间来查找资料、整理文献、检查语法和格式等。为了帮助大家轻松完成论文写作&#xff0c;现在有了许多写作…

【QT入门】Qt自定义控件与样式设计之QPushButton常用qss

往期回顾 【QT入门】Qt自定义控件与样式设计之qss介绍(Qt style sheet)-CSDN博客 【QT入门】 Qt自定义控件与样式设计之qss选择器-CSDN博客 【QT入门】 Qt自定义控件与样式设计之QLineEdit的qss使用-CSDN博客 【QT入门】Qt自定义控件与样式设计之QPushButton常用qss 这里我们主…

本地电脑渲染不行怎么解决?自助式渲染助你渲染无忧

有时候&#xff0c;即使购买了昂贵的新电脑&#xff0c;我们也可能会遇到渲染速度缓慢、画质不佳或渲染失败等问题。这些问题可能由多种因素引起。针对该问题&#xff0c;为大家推荐了自助式的渲染&#xff0c;解决你本地电脑渲染不佳问题。 电脑渲染不行原因 新电脑渲染效果不…

亚马逊AWS上怎么创建Linux 服务器?操作难不难?

AWS(Amazon Web Services)是全球领先的云服务器提供商之一。你可以使用 AWS 平台在一分钟内设置完服务器。在 AWS 上&#xff0c;你可以微调服务器的许多技术细节&#xff0c;如 CPU 数量&#xff0c;内存和磁盘空间&#xff0c;磁盘类型(更快的 SSD 或者经典的 IDE)等。关于 A…