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

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.rhkb.cn/news/300907.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

鸿蒙学习记录

问题小测记录 总结链接:小测总结 学习笔记:鸿蒙开发学习记录 1、 main_pages.json存放页面page路径配置信息。 2、在stage模型中,下列配置文件属于AppScope文件夹的是? app.json5 3、module.json5配置文件中,包含…

Django之REST Client插件

一、接口测试工具介绍 在开发前后端分离项目时,无论是开发后端,还是前端,基本都是需要测试API接口的内容,而目前我们需要开发遵循RESTFul规范的项目,也是必然的(自己不开发前端页面)。 在网上有很多这样的工具,常用的postman,但还是需要下载安装。在这我们介绍一个VSCod…

绿联 安装cookiecloud,进行cookie的跨浏览器同步

绿联 安装cookiecloud,进行cookie的跨浏览器同步 1、镜像 easychen/cookiecloud:latest 2、安装 2.1、基础设置 重启策略:容器退出时总是重启容器。 2.2、网络 桥接即可。 2.3、存储空间(可选) 存储空间可以不配置&#xff…

Redis单线程 VS 多线程

一、Redis 为什么选择单线程? 这种说法其实并不严谨,为什么这么说呢? Redis的版本有很多 3.x、4.x、6.x,版本不同架构也不同的,不限定版本问是否单线程也是不太严谨。 版本3.x,最早版本,也就…

单片机为什么还在用C语言编程?

单片机产品的成本是非常敏感的。因此对于单片机开发来说,最重要的是在极其有限的ROM和RAM中实现最多产品的功能。或者反过来说,实现相同的产品功能,所需要的ROM和RAM越小越好,在开始前我有一些资料,是我根据网友给的问…

centos安装使用elasticsearch

1.首先可以在 Elasticsearch 官网 Download Elasticsearch | Elastic 下载安装包 2. 在指定的位置(我的是/opt/zhong/)解压安装包 tar -zxvf elasticsearch-7.12.1-linux-x86_64.tar.gz 3.启动es-这种方式启动会将日志全部打印在当前页面,一旦使用 ctrlc退出就会导…

【Leetcode每日一题】 动态规划 - LCR 166. 珠宝的最高价值(难度⭐⭐)(52)

1. 题目解析 题目链接:LCR 166. 珠宝的最高价值 这个问题的理解其实相当简单,只需看一下示例,基本就能明白其含义了 2.算法原理 想象一下,你正在玩一个寻宝游戏,游戏地图是一个二维网格,每个格子都藏有一…

【Linux ARM 裸机】开发环境搭建

1、Ubuntu 和 Windows 文件互传 使用过程中,要频繁进行 Ubuntu 和 Windows 的文件互传,需要使用 FTP 服务; 1.1、开启 Ubuntu 下的 FTP 服务 //安装 FTP 服务 sudo apt-get install vsftpd //修改配置文件 sudo vi /etc/vsftpd.conf//重启…

易宝OA ExecuteSqlForDataSet SQL注入漏洞复现

0x01 产品简介 易宝OA系统是一种专门为企业和机构的日常办公工作提供服务的综合性软件平台,具有信息管理、 流程管理 、知识管理(档案和业务管理)、协同办公等多种功能。 0x02 漏洞概述 易宝OA ExecuteSqlForDataSet接口处存在SQL注入漏洞,未经身份认证的攻击者可以通过…

设计模式深度解析:AI大模型下的策略模式与模板方法模式对比解析

​🌈 个人主页:danci_ 🔥 系列专栏:《设计模式》《MYSQL应用》 💪🏻 制定明确可量化的目标,坚持默默的做事。 策略模式与模板方法模式对比解析 文章目录 🌟引言🌟Part 1:…

neo4j图数据库下载安装配置

neo4j下载地址Index of /doc/neo4j/3.5.8/ 1.说明:jdk 1.8 版本对应的 neo4j 数据库版本 推荐安装3.X版本 2.配置系统环境变量 3.启动 neo4j.bat console 4.访问

智慧城市治理:构建全域覆盖的城市时空感知体系

TSINGSEE青犀AI算法中台是一款平台型产品,专注于提供各行业中小场景部署解决方案。平台具备接入广、性能强、支持跨平台、芯片国产化等特点,可提供丰富的视图接入能力和智能分析能力。 平台采用了多项IT高新技术,包括视频编解码技术、嵌入式…

《深入浅出多模态》:多模态经典模型CLIP

🎉AI学习星球推荐: GoAI的学习社区 知识星球是一个致力于提供《机器学习 | 深度学习 | CV | NLP | 大模型 | 多模态 | AIGC 》各个最新AI方向综述、论文等成体系的学习资料,配有全面而有深度的专栏内容,包括不限于 前沿论文解读、资料共享、行业最新动态以、实践教程、求职…

10 Python进阶:MongoDB

MongoDb介绍 MongoDB是一个基于分布式架构的文档数据库,它使用JSON样式的数据存储,支持动态查询,完全索引。MongoDB是NoSQL数据库的一种,主要用于处理大型、半结构化或无结构化的数据。以下是MongoDB数据库的一些关键特点和优势&a…

k8s单节点部署,容器运行时使用containerd

环境 系统 : entOS Linux release 7.9.2009 (CoreIP:192.168.44.177 硬件要求:控制平面最少需要 2c2g 安装前环境准备 如果是集群部署还需要配置时间同步 关闭防火墙 systemctl disable firewalld关闭selinux setenforce 0sed -i s/SELI…

深入浅出 -- 系统架构之微服务架构选型参考图

技术选型架构图 是一个用于展示项目中所采用的各种技术和组件之间关系的图表。 它通常包括以下几个部分: 1. 项目名称和描述:简要介绍项目的背景和目标。 2. 技术栈:列出项目中使用的主要技术和工具,如编程语言、框架、数据库…

RabbitMQ Docker 安装与应用

1.官方镜像 该镜像包含用户操作界面 2.Docker运行,并设置开机自启动 docker run -d --restartalways --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.10-management 默认登录账户和密码 guest 3、使用 队列和交换机绑定

理解PostgreSQL中的postmaster.pid

在PG中,一个简要的体系结构图可以大致画成下边的样子: Server端基本上分成backend process和若干background process。这些process都是一个名为postmaster进程的子进程。而postmaster则是postgres进程的别名。 进程概况 [14:42:08-postgrescentos1:/pg…

Ubuntu22.04平台编译完美解决问题“error: GLSL 4.5 is not supported.”【GLSL(OpenGL着色器语言)】

GLSL介绍 GLSL(OpenGL着色器语言)是用于编写OpenGL着色器程序的语言。GLSL 4.5 是 GLSL 的一个版本,引入了许多新的特性和改进,旨在提高着色器编程的灵活性和性能。GLSL 4.5 工具通常是用于编写、调试和优化 GLSL 4.5 着色器代码…

SinoDB数据库导入导出工具unload/load

unload/load是最常使用的最简单的数据导入、导出工具,支持的数据格式为以固定分隔符(如“|”为默认的分隔符)分隔的文本文件。 1. unload 数据导出 使用方法如下: unload to filename’ [DELIMITER ‘delimiter’] SELECT Statement; 其中: filename可…