一共需要三个类:手机系统抽象类PhoneOS
、Android
系统与IOS
系统两个子类。
PhoneOS
手机系统抽象类,提供一个install()
安装软件的方法
/**
* @create on 2020/6/8 23:32
* @description 手机系统
* @author mrdonkey
*/
abstract class PhoneOS {
/**
* 安装方法
*/
open fun install(){}
}
Android
/**
* @create on 2020/6/8 23:34
* @description android品牌
* @author mrdonkey
*/
open class Android : PhoneOS() {
}
IOS
/**
* @create on 2020/6/8 23:35
* @description IOS品牌
* @author mrdonkey
*/
open class IOS : PhoneOS() {
}
完成!
AndriodBilibili
/**
* @create on 2020/6/8 23:41
* @description android版Bilibili
* @author mrdonkey
*/
class AndroidBilibili :Android(){
override fun install() {
println("----->安装Android版Bilibili")
}
}
AndroidLOL
/**
* @create on 2020/6/8 23:44
* @description android版LOL
* @author mrdonkey
*/
class AndroidLOL : Android() {
override fun install() {
println("----->安装Android版LOL")
}
}
IOS的代码同上。
若在上面的程序再加一个效率软件,那么分别得在Android
和IOS
下新增。若是增加一个新的手机系统,那么就得copy现有系统下的各个软件分支。目前看起来还不算复杂,若软件分支一多、手机系统增加的话,修改就过于麻烦。
按手机软件进行分类UML
,这样的做法其实与程序2的结构差别不大,增加手机软件的分支或手机系统,也难免多而烦的修改。
之前的设计: 用面向对象的继承
进行设计,先有一种手机系统,多种系统就抽象出一个手机系统抽象类PhoneOS
,对于每一类软件,就都各自继承各自的系统。再就是从手机的软件分类角度去划分。
分析:
很多情况一味的使用继承
会带来麻烦。对象的继承关系是在编译时就定义好了,所以无法在运行时改变从父类继承的实现。子类的实现与它父类的实现有非常紧密的依赖关系,以至于父类实现中的任何变化必然会导致子类发生变化。让你需要复用子类时,如果继承下来的实现不适合解决新的问题。,则父类必须重写或被其他更合适的类替换。
这种依赖关系限制了灵活性与复用性。对于上述的继承结构,如果不断新增软件分类或系统,类的越来越多。使用继承的条件:
继承关系,是一种强耦合的结构,父类变子类必须变。所以一定要是‘is a’关系时再考虑使用继承,而不是任何时候都去使用。改进:
学会运用合成(组合)/聚合原则
,即优先使用对象合成/聚合,而不是类继承。合成(也叫组合)与聚合都是关联的特色种类。
合成:
表示一种强的‘拥有’关系,体现了部分和整体部分的关系,部分和整体的生命周期一样。
聚合:
表示一种弱的‘拥有’关系,体现的是A对象可以包含B对象,但B对象不一定是A对象的一部分。
合成关系
。聚合关系
。优先使用对象的合成/聚合将有助于保持每个类被封装,并被集中在单个任务上。
这样的类和类的层次会保持比较小的规模,并不太可能增长为不可控制的庞然大物。学会使用对象的职责,而不是结构来考虑问题。
在之前的程序中,利用有手机系统、手机软件分类两块;我们就可以将这两块进行拆分成一个单元,通过聚合关系将手机系统关联手机软件
分类(因为一个系统拥有多种软件分类),它们是聚合关系;拆成小单元后,每一个模块可以各自变化,不影响其他的模块。
应用现在的结构设计,即便新增,也不会修改原来的代码(开放-封闭原则
)。
它们之间有一条聚合线,像一座桥!这种设计模式就叫做桥接模式
。
桥接模式
(Bridge),将抽象部分与它的实现部分分类,使它们都可以独立变化。
这里说的抽象与它的实现分离并不是让抽象类与其子类分离,而是指抽象类用来实现自己的对象(手机系统)和子类用来实现自己对象(软件分类),拆分原本的继承层次,就是分离。
核心意图:
把每个实现(如软件分类)都独立出来,让他们各自变化。这使得每种实现的变化不影响其他的实现,从而达到应对变化的目的。
Implementor
实现类
/**
* @create on 2020/6/9 23:26
* @description 实现部分
* @author mrdonkey
*/
abstract class Implementor {
abstract fun operation()
}
ConcreteImplementorA
和ConcreteImplementorB
具体实现类
/**
* @create on 2020/6/9 23:30
* @description 具体实现A
* @author mrdonkey
*/
class ConcreteImplementorA:Implementor() {
override fun operation() {
println("----->具体实现A的方法执行")
}
}
ConcreteImplementorB
如上,省略了。
Abstraction
抽象类
/**
* @create on 2020/6/9 23:28
* @description 抽象部分
* @author mrdonkey
*/
open class Abstraction {
lateinit var implementor: Implementor
open fun operation() {
if (this::implementor.isInitialized) {//如果被初始化才执行
implementor.operation()
}
}
}
RefinedAbstraction
被提炼的抽象类
/**
* @create on 2020/6/9 23:29
* @description 被提炼的抽象
* @author mrdonkey
*/
class RefinedAbstraction:Abstraction() {
override fun operation() {
implementor.operation()
}
}
Client
客户端
/**
* @create on 2020/6/9 23:35
* @description 客户端类
* @author mrdonkey
*/
class Client {
companion object {
@JvmStatic
fun main(args: Array<String>) {
val abstraction = RefinedAbstraction()
abstraction.implementor = ConcreteImplementorA()
abstraction.operation()
abstraction.implementor = ConcreteImplementorB()
abstraction.operation()
}
}
}
桥接模式:实际就是实现系统可能有多角度分类。每一种分类都可能变化,那么就把这种多角度分离出来让它们独立变化,减少他们的耦合。