前言
最近加班是真的很多,无法腾出大块时间来学习。设计模式又不想只更到一半半途而废,想了又想,决定精简,保证大家一看就懂(看完就忘…)。设计模式分创建型模式,结构型模式和行为型模式。到目前为止,创建型模式已经讲完,对于剩下的模式,会分成这两大块统一讲解。
行为型模式
行为型模式主要关注的点事类的动作,各个类之间相互的作用,将职责划分清楚,使我们的代码更加的清晰。
策略模式
定义一组算法,将每个算法都封装起来,并且使他们之间可以互换。
策略模式是一个出现频率很高,但又很简单的模式。下面的场景是我们要出去旅游,但是可以选择出去旅游的交通方式,比如坐飞机,坐火车或者步行。废话不再多说,直接上码:
public interface Strategy {
void travel();
}
public class Walk implements Strategy {
@Override
public void travel() {
System.out.println("步行去旅行");
}
}
public class Train implements Strategy {
@Override
public void travel() {
System.out.println("坐火车去旅行");
}
}
public class Airplane implements Strategy {
@Override
public void travel() {
System.out.println("坐着飞机去旅行");
}
}
public class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void execute(){
strategy.travel();
}
}
public class Client {
public static void main(String[] args) {
Context context = new Context(new Airplane());
context.execute();
}
}
console:
坐着飞机去旅行
策略模式的优点非常明显,在现有的系统中增加一个策略太容易,只要实现接口就可以了,其他都不用修改,类似于一个可以反复拆卸的插件,符合ocp原则。其缺点就是每个策略都是一个类,复用性很小,复杂的业务场景容易发生类数量爆炸,并且策略模式和迪米特法则是违背的,我们看下上面的clent场景类(相当于项目中的高层调用模块),我只是想使用一个策略,凭什么就要了解这个策略呢?那要封装类就没有意义了,这是策略模式的一个大缺点,所以策略模式很少单独出现,大多结合其他模式来弥补这个缺陷,如工厂方法或者代理模式。
观察者模式
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新
策略模式也叫发布订阅模式,其中最主要额角色名称就是subject被观察者和observer观察者。接下来会模拟一个场景,学校作为被观察者发布放假的消息,家长和学生作为观察者实现自己的逻辑:
/**
* 主题(被观察者)需要实现的职责,就是可以动态的增加删除观察者。
* 根据主题的状态通知所有的观察者Observer
*/
public abstract class Subject {
private Vector<Observer> observerList = new Vector<>();
private int status;
public void addObserver(Observer observer){
observerList.add(observer);
}
public void delObserver(Observer observer){
observerList.remove(observer);
}
public void notifyAllObserver(){
observerList.forEach(observer -> {
observer.update();
});
}
}
public class SchoolSubject extends Subject {
//学校宣布放七天假期
public void haveSevenDaysHoliday(){
System.out.println("学校:从今天开始放假,所有学生七天后返校");
super.notifyAllObserver();
}
}
public interface Observer {
//观察者,被通知了实现其自己的逻辑
void update() ;
}
public class Parent implements Observer {
@Override
public void update() {
System.out.println("家长:这倒霉孩子怎么又放假了,坚决不能让他玩王者荣耀....");
}
}
public class Student implements Observer {
@Override
public void update() {
System.out.println("学生:哇哈哈,终于有时间打王者荣耀喽");
}
}
public class Client {
public static void main(String[] args) {
SchoolSubject subject = new SchoolSubject();
Student student = new Student();
Parent parent = new Parent();
subject.addObserver(student);
subject.addObserver(parent);
subject.haveSevenDaysHoliday();
}
}
console:
学校:从今天开始放假,所有学生七天后返校
学生:哇哈哈,终于有时间打王者荣耀喽
家长:这倒霉孩子怎么又放假了,坚决不能让他玩王者荣耀....
虽说观察者和被观察者是耦合在一起的,但是不管是扩展增加观察者还是被观察者都非常容易。并且根据单一职责原则,每个类的职责都是唯一,需要一套机制将类串联起来形成一个真实的场景,就比如学校公布放假,孩子想着玩游戏,家长为了孩子的成绩禁止孩子玩游戏,然后因为学校放假我就不玩了(小学生,你懂得),这样就形成了一个触发机制。其缺点就是执行效率低下,需异步执行。从原理上看,我们常用的mq就是观察者模式的升级版。
责任链模式
使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。
责任链我们很容易想到链表结构,实际上责任链就是一种基于链表的处理方式。当一个请求过来,调用链表的头结点,处理之后再往后流转。
有这么一个场景:路飞饿了打开美团准备订外卖。选中吃的后,进行下单,首先校验是否在营业时间内,然后校验是否在配送范围内,然后校验是否有货等等,设定责任链都通过后,路飞才能订到饭。
//链表内结点的基类
public abstract class RuleHandler {
protected RuleHandler successor;
public abstract void echo(Context context);
public void setSuccessor(RuleHandler successor) {
this.successor = successor;
}
public RuleHandler getSuccessor() {
return successor;
}
}
//判断营业时间
public class TimeHandler extends RuleHandler {
@Override
public void echo(Context context) {
//营业时间判断
if (context.isTimeInRange()){
if (this.getSuccessor()!=null){
this.getSuccessor().echo(context);
}
}else {
throw new RuntimeException("不在营业时间内");
}
}
}
//判断是否在配送范围内
public class AreaHanler extends RuleHandler {
@Override
public void echo(Context context) {
if (context.isAreaInRange()){
if (this.getSuccessor()!=null){
this.getSuccessor().echo(context);
}
}else {
throw new RuntimeException("不在配送范围内");
}
}
}
//判断库存
public class StockHandler extends RuleHandler {
@Override
public void echo(Context context) {
if (context.hasStock()){
if (this.getSuccessor()!=null){
this.getSuccessor().echo(context);
}
}else {
throw new RuntimeException("挑选的商品已经卖完");
}
}
}
客户端调用逻辑:
public class Client {
public static void main(String[] args) {
RuleHandler timeHandler = new TimeHandler();
RuleHandler areaHandler = new AreaHanler();
RuleHandler stockHandler = new StockHandler();
timeHandler.setSuccessor(areaHandler);
areaHandler.setSuccessor(stockHandler);
timeHandler.echo(new Context());
}
}
代码非常简单,责任链模式的重点是在链上,由一条链去处理请求并返回相应的结果。它非常显著的优点就是将请求和处理分开,两者解耦,提高系统的灵活性。缺点就是链表遍历必须从链头到链尾,存在性能问题。采用了类似递归调用的方式,增大了读懂逻辑的难度
模板方法模式
在之前的博客里已经长篇大论过,故直接拿过来。
模板方法
状态模式
当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。
状态模式的核心是封装,通过状态的变更引起行为的变更。现在大家来思考一下,电脑有三种状态,分别为关机,已启动。
//代表环境,也就是状态的主体
public class Context {
//所有的电脑状态
public final static OpenState OPEN = new OpenState();
public final static CloseState CLOSE = new CloseState();
//电脑当前的状态
private ComputerState currentState;
public ComputerState getCurrentState() {
return currentState;
}
public void setCurrentState(ComputerState currentState) {
this.currentState = currentState;
this.currentState.setContext(this);
}
public void openMachine() {
this.currentState.openMachine();
}
public void closeMachine() {
this.currentState.closeMachine();
}
}
//状态基类,真实的电脑逻辑封装在了状态中
public abstract class ComputerState {
protected Context context;
public void setContext(Context context) {
this.context = context;
}
public abstract void openMachine();
public abstract void closeMachine();
}
public class OpenState extends ComputerState{
@Override
public void openMachine() {
System.out.println("电脑开机...");
}
@Override
public void closeMachine() {
super.context.setCurrentState(Context.CLOSE);
super.context.getCurrentState().closeMachine();
}
}
public class CloseState extends ComputerState {
@Override
public void openMachine() {
super.context.setCurrentState(Context.OPEN);
super.context.getCurrentState().openMachine();
}
@Override
public void closeMachine() {
System.out.println("电脑关机...");
}
}
客户端测试类:
public class Client {
public static void main(String[] args) {
Context context = new Context();
context.setCurrentState(Context.OPEN);
context.openMachine();
context.closeMachine();
}
}
状态模式的优点有结构清晰,避免了各种条件的判断,省掉了swtich…case,if…else语句的使用,提升了代码的可读性。遵循了单一职责原则和开闭原则,每个状态都是一个子类,增加状态只需增加一个状态子类,修改状态,修改对应的子类就可以了。封装性非常好,客户端不需知道内部状态的转换以及相应的逻辑.其缺点就是状态子类会太多,并且我们可以将状态存储到数据库中,然后根据状态执行相应的操作,这也是一种不错的实现方式,具体如何使用看大家个人喜好了。
总结
本章的行为型模式总结了策略模式、观察者模式、责任链模式、模板方法模式和状态模式,其实不仅于此,还有备忘录模式和命令模式等,但因其使用场景有限,就不做一一探讨了,留给读者自己学习~.~