「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战」
桥接模式
桥接模式(bridge pattern)
这里的桥,其实很形象:它沟通了我们两个概念之间的信息。
实际上桥接模式说起来很复杂,其实很简单,我们用下面的数据库驱动的例子解释一下。
- 当然,下面的数据库操作,一般情况可能会替换成接口,达到更大程度的抽象
我们定义一个接口和一个类:
public interface 数据库连接驱动{}
public class 数据库操作{}
我们知道(不知道的你现在知道了):
-
连接到不同数据库(mysql?oracle?或者其他的数据库),需要的连接方式往往不同,执行的操作也不同。
- 因此对于不同的数据库,我们总需要实现不同的方法,来适应这个差异。
那么:
- 如果使用继承的方法来实现对于不同数据库的连接,那么我们的类未免太多了。
因此,在这里我们采用组合来替换继承。
我们对于上面的接口,添加一点描述:
public interface 数据库连接{
void 执行操作();
}
public class mySQL连接 implements 数据库连接{
//....
}
public class 数据库操作{
private 数据库连接 持有的连接;
public void 设定连接(数据库连接 a){this.持有的连接 = a;}
public Object 执行操作(Object[] params){
return this.持有的连接.执行操作();
}
}
这样就是桥接模式的一个简单实现了,这里我们不难看出:
- 桥接模式,实际上是将对应的操作交给了类中对应的对象进行操作的。
这样的额外好处是:
- 只要实现了接口,在上面的例子里我们就不用关注用的是什么数据库连接了,我直接执行操作
当然,我们也降低了上面所说的类爆炸的风险,实际上这里类爆炸的问题是:
- 错误地将不够抽象的对象,使用继承拼装在一起,造成了类过多的现象
外观模式
外观模式:facede,也叫做门面模式
- 和DDD关系:领域内聚的基础
其实外观模式,最重要的就是遵循了
合成复用原则: 尽量使用合成、聚合,而不是继承。
例如:
我们有:
- 握把
- 轮子
- 踏板
- 链条
以及等等等的内聚的对象信息。
我们就可以把这几个东西组合成一个更大的概念:自行车
在外观模式中,对于以上信息内容的映射为:
public class 自行车{
握把
轮子
踏板
链条
public void 骑{
if(踏板动)
链条动
轮子动
if(握把.没握稳)
车开始晃,可能摔倒
}
}
外观模式,其实就是通过把一些内聚紧密的领域(通俗点来说概念的映射)聚合在一起,变成一个更大的领域,或者更具体的业务逻辑,这样子的好处是:
- 不用破坏原本已经内聚紧密的模型
- 可以复用原来验证过的逻辑
通过描述,我们可以发现外观模式是一个在编程实践中运用最广泛的设计模式之一了:
- 为了我们复杂业务逻辑的简化,我们总会将一些和业务逻辑无关的代码封装起来,降低业务代码的复杂性以及和不同层级之间代码的耦合程度
- 而这些封装起来的代码,一般来说我们都会将其封装到相关的类中,使其尽可能的内聚
享元模式
享元模式的引入,是为了解决这样的问题:
- 程序中存在着大量的对象,但对象之中有一大部分内容都是完全相同且不发生变更的。
- 那么,如果我们对于这些对象都保存了这些不变更的信息,随着这类对象的增加,内存就会因为这些东西而导致可用内存降低,甚至导致OOM。
享元模式是这样子解决这个问题的:
- 将重复的信息抽象成若干确定个对象
- 将这些对象固化(使用工厂保存缓存是比较好的方法)
- 需要这些信息的对象,就使用这些固化信息的引用,那么内存使用率就降低了。
可能描述得不是很好,那么举个最常见的例子:
-
我们常用的网盘,就是享元模式的应用之一
-
如果是跟NAS一样:
对于每个人的文件,我们都保存一份完整的文件
那么,光是文件的内容,服务器就很难承受。
因此,网盘常见的策略就是:
- 只保存一份文件(不考虑backup),用户在对文件的操作中,其实是对自己能访问的信息中,对于那些文件的引用进行的操作。这样子就能节省下大量的磁盘空间。