观察者模式
又可以称为发布订阅模式,主要用于程序内部解耦。比如在分布式系统中,某条记录更新了,需要同步到缓存,还要落地到数据库,可能还要发送通知等等。
常见的写法可能如下:
update(记录A){
记录更新;
f{同步缓存};
f{落地数据库};
f{发送邮件通知};
}
这样写,代码很容易冗余,而且阅读很难理解,任务拆分也不方便。
使用观察者模式,可以对
f{同步缓存};
f{落地数据库};
f{发送邮件通知};
这里的方法进行抽象,定义统一的接口(或者抽象类)。
for(F f:fList){
f.update(记录);
}
装饰者模式
对扩展开放,对修改关闭的程序设计基本原则。是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。装饰者模式类也会有爆发性的可能。
JavaIO就是标准的装饰者模式。
装饰者模式也是对继承模式使用的一种总结。通过指定主体类和统一的行为接口,提供丰富的组装。
数据集;
f(){
if(是否去重)
f{去重}(数据集);
if(是否添加汇总行)
f{添加汇总行}(数据集);
if(是否格式替换)
f{格式替换}(数据集);
}
这种非必须的操作,可以使用装饰者模式抽象成类,不过使用装饰者模式不一定比上述模式来的更好。还是要具体场景具体分析。
工厂模式
封装对象的创建过程,这是最简单的模式,也是让人觉得最没用的,当一个对象的创建过于复杂和多变,就需要使用工厂模式。比如常见的数据库会话session的创建。
以下摘抄自知乎:
假设有代码包A和代码包B,代码包B是代码包A的调用者,A向B暴露接口InterfaceA。在A的内部结构中,实现了InterfaceA的有ClassA1,ClassA2,ClassA3,……ClassA100。但是B并不关心这些,因为对于B来说,A的功能只有一个,就是InterfaceA。这个时候,B想要使用一个InterfaceA的实现,想要new一个出来,但又不想与代码包A中的复杂的构造逻辑耦合,怎么办?只能向代码包A中传递参数,交给代码包A自己选择到底是那个ClassA1还是A100被new出来。而这个对构造过程进行选择的逻辑,就是工厂。
单例模式
一般使用单例模式要满足以下条件:
1、单例类确保自己只有一个实例。
2、单例类必须自己创建自己的实例。(构造方法变成private)
3、单例类必须为其他对象提供唯一的实例。
现实场景中,一些全局统计类的功能会使用到单例模式。
命令模式
这个模式个人觉得是最常用也是最需要不断总结的模式。本来操作系统就是一种命令模式,CPU执行时,无非就是接受指令,指令分为操作类型和操作数据。
在实际场景中,可以基于命令模式实现分布式的业务事务。
Stack<Command> stack;
function exec(Command c)
{
try{
c.execute();
stack.push(c);
}catch(exection e){
//以此回滚Stack中的操作。
}
}
流程化的操作,都可以封装成命令模式,进行流程监控等信息记录。
适配器模式与外观模式
这个在项目中比较常见,本身系统已经抽象好对外接口,现在要对接多个源系统,就需要编写适配器。适配器模式本身很简单,难的是系统通用接口的抽象,需要仔细考虑其中的业务细节。
模板方法模式
定义一个操作中的算法骨架,而将一些实现步骤延迟到子类当中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
个人觉得该模式比较简单,每个行业都有一套固有的模式,对模式中每个步骤又是千变万化的。
迭代器模式
操作集合对象一般使用迭代器(Iterator )。
而集合对象后端实现使用了不同的算法和数据结构,通过迭代器模式把这些实现屏蔽掉,让用户用起来更简单。
尚未在实际项目中使用到这种模式。
状态模式
状态模式相对比较复杂,它提供了一种对物质运动的另一个观察视角,通过状态变更促使行为的变化,就类似水的状态变更一样,一碗水的初始状态是液态,通过加热转变为气态,状态的改变同时也引起体积的扩大,然后就产生了一个新的行为。
状态模式常见的就是登录场景,对于登录用户和非登录用户或者会员用户,是有不同的操作权限的。通过抽象用户的状态,增强代码的可读性和易用性。
代理模式
和适配器模式的主要区别,代理模式中代理类的接口和原类是一致的。