设计模式 -行为类模式
命令模式
- 5个角色:
- 客户端 Client,负责构建所有对象
- 具体命令 ConcreteCommand(处理某一个行为),多种行为多个实例化对象,但是自己并不执行,调用Receiver去执行方法。也是模式的核心所在,既可以实现不同功能的解耦,又可以实现直接调用所不能提供的额外功能。
- Commmand
- 触发器(请求者) Invoker
- 接收执行者 Receiver
原理:Client不直接调用Reciver,而是通过Invoker和ConcreteCommand作为中间媒介去调用Reciver,ConcreteCommand存在的意义是做一些方法增强的操作,比如记录、事务、回退等功能,Invoker的作用是组装需要的Commands,把无关的行为屏蔽掉。
过程:
- 客户端 创建N个具体的命令且指定Receiver
- 客户端 把创建好的命令对象装配成一个 Invoker
- 客户端 调用Invoker里面的方法,间接的通过ConcreteCommand来操作Receiver执行命令
- 使用场景:比如要对行为进行”记录日志、操作全部撤销/最近一个操作回退、事务”等处理,可以实现二者之间的松耦合。
支持回退功能的命令模式
commond接口实现 excute(); un()功能。
不同的功能模块去实现这2个方法,但是每个模块额外添加一个数组或者栈去记录操作顺序,然后就可以提供顺序撤销的功能了。
http://www.cnblogs.com/JsonShare/p/7206513.html
Client
public class Client {public static void main(String[] args) {//创建接收者Computer computer = new Computer();//创建具体命令并且指定接收者DirCommand dirCommand = new DirCommand(computer);FileCommand fileCommand = new FileCommand(computer);//创建请求者Invoker invoker = new Invoker(fileCommand,dirCommand);/***********创建目录及撤销**************///创建目录invoker.createDir("C:\\Users\\502764158\\Desktop\\io\\aa");invoker.createDir("C:\\Users\\502764158\\Desktop\\io\\bb");invoker.createDir("C:\\Users\\502764158\\Desktop\\io\\cc");invoker.undoDir();invoker.undoDir();invoker.undoDir();invoker.undoDir();}}Recevier(支持2个模块 文件和目录模块的创建和删除)
public class Computer {public void createDir(String path){File dir = new File(path);if (dir.exists()) {System.out.println("创建目录 " + path + " 失败,目标目录已经存在");}else{//创建目录if (dir.mkdirs()) {System.out.println("创建目录 " + path + " 成功");} else {System.out.println("创建目录 " + path + " 失败");}}}public void deleteDir(String path){File dir = new File(path);if(dir.exists()) {if(dir.delete()){System.out.println("删除目录 " + path + " 成功");}else{System.out.println("删除目录 " + path + " 失败");}}else{System.out.println("删除目录 " + path + " 失败,目标目录不存在");}}public void createFile(String name){}public void deleteFile(String name){}}Command
public interface Command {void execute(String path);void undo();}DirCommand
public class DirCommand implements Command{private DirCommand(){};private Computer computer;DirCommand(Computer computer){this.computer=computer;}List<String> list=new ArrayList();@Overridepublic void execute(String path) {computer.createDir(path);list.add(path);}@Overridepublic void undo() {if(list.size()>0){String path=list.get(list.size()-1);computer.deleteDir(path);list.remove(list.size()-1);}else{System.out.println("没有需要撤销的操作!");}}}FileCommand
public class FileCommand implements Command{private FileCommand(){};private Computer computer;FileCommand(Computer computer){this.computer=computer;}List<String> list=new ArrayList();@Overridepublic void execute(String path) {}@Overridepublic void undo() {}}Invoker
public class Invoker {private FileCommand fileCommand;private DirCommand dirCommand;Invoker(FileCommand fileCommand,DirCommand dirCommand){this.fileCommand=fileCommand;this.dirCommand=dirCommand;}public void createDir(String path){dirCommand.execute(path);}public void undoDir(){dirCommand.undo();}public void createFile(String path){fileCommand.execute(path);}public void undoFile(){fileCommand.undo();}}
责任链模式
IF-ELSE的高级版本。为请求创建了一个接收者对象的单向链表,通常每个接收者都包含对下一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。从而对请求的发送者和接收者进行解耦。
业务场景
有一个银行的借款系统可以帮助用户借款,负责该系统的有职员,组长还有经理,他们的等级由低到高,并且他们能够允许借款的额度也是从低到高的,分别是:
- 职员最高可以批准 5000 元的借款额度
- 组长最高可以批准 20000 元的借款额度
- 经理最高可以批准 100000 元的借款额度
当有转账的请求过来时,先由等级低的员工处理,若无法处理,则将请求移交给上级处理。
public void test(Request request) {int money = request.getRequestMoney();if(money <= 1000) {Clerk.response(request);} else if(money <= 5000) {Leader.response(request);} else if(money <= 10000) {Manager.response(request);}}IF-ELSE代码臃肿: 实际应用中的判定条件通常不是这么简单地判断金额,也许需要复杂的操作,也许需要查询数据库等等,这就会产生许多额外的代码,如果判断条件再比较多的话,那么代码就会大量地堆积在同一个文件中。一坨判断看的眼花。
- IF-ELSE耦合度高:如果我们想继续添加处理请求的类,那么就需要添加 else if 的判定条件;另外,这个条件判定的顺序也是写死的。如果想改变顺序,那么也只能修改这个条件语句。
利用责任链模式,请求者不需要知道谁是真正的接收者,而且接收者A只需要知道他的下线,不需要知道所有的接收者。
实现
- 关键代码:Handler 里面聚合它自己,在 HanleRequest 里判断是否合适,如果没达到条件则向下传递,向谁传递之前 set 进去。
- 何时使用:在处理消息的时候以过滤很多道。
- 缺点:
- 不能保证请求一定被接收。
- 系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。
- 可能不容易观察运行时的特征,有碍于除错。
实现代码
抽象一个处理模型
public abstract class AbstractLogger {public static int INFO = 1;public static int DEBUG = 2;public static int ERROR = 3;protected int level;//责任链中的下一个元素protected AbstractLogger nextLogger;public void setNextLogger(AbstractLogger nextLogger){this.nextLogger = nextLogger;}public void logMessage(int level, String message){if(this.level <= level){write(message);}if(nextLogger !=null){nextLogger.logMessage(level, message);}}abstract protected void write(String message);}创建不同的Node
public class ErrorLogger extends AbstractLogger {public ErrorLogger(int level){this.level = level;}@Overrideprotected void write(String message) {System.out.println("Error Console::Logger: " + message);}}public class FileLogger extends AbstractLogger {public FileLogger(int level){this.level = level;}@Overrideprotected void write(String message) {System.out.println("File::Logger: " + message);}}public class ConsoleLogger extends AbstractLogger {public ConsoleLogger(int level){this.level = level;}@Overrideprotected void write(String message) {System.out.println("Standard Console::Logger: " + message);}}把link按照业务逻辑串起来
public class LoggerChain {static AbstractLogger getChainOfLoggers(){AbstractLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR);AbstractLogger fileLogger = new FileLogger(AbstractLogger.DEBUG);AbstractLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO);errorLogger.setNextLogger(fileLogger);fileLogger.setNextLogger(consoleLogger);return errorLogger;}}用户端调用
public class Client {public static void main(String[] args) {AbstractLogger loggerChain = LoggerChain.getChainOfLoggers();loggerChain.logMessage(AbstractLogger.INFO,"This is an information.");loggerChain.logMessage(AbstractLogger.DEBUG,"This is an debug level information.");loggerChain.logMessage(AbstractLogger.ERROR,"This is an error information.");}}
观察者模式
https://zhuanlan.zhihu.com/p/25045567
参与者
这种互相抽象的模式,实现了高度的解耦和灵活。
- 被观察者(Subject):知道它的通知对象,事件发生后会通知所有它知道的对象,提供添加删除观察者的接口。
- 观察者(Observer):提供通知后的更新事件
- 具体被观察者(ConcreteSubject):被观察者具体的实例,存储观察者感兴趣的状态。
- 具体观察者(ConcreteObserver):观察者的具体实现。
观察者模式适用于:
- 当一个对象在不知道对方具体是如何实现时需要通知其它对象(因为添加的观察者是抽象类,具体如何实现要看注入的具体观察者
- 当一个对象改变需要通知不确定数的对象时
Demo业务场景
场景:你被要求开发一个简单的股票监控应用程序。初始要求是:
- 股票有一个符号名称和当前价格。
- 投资者可以监控它的当前价值股票。
- 当股票价格变化时,所有监测的股票投资者都被告知变化。
通过Stock和Investor同时抽象,可以实现一个股民可以观察多个股票,一个股票价格变动可以通知多个股民
实现代码
把股票抽象起来
public abstract class Stock {private Vector<Investor> investors = new Vector<Investor>();protected int price = 0;public void addInvestor(Investor i){this.investors.add(i);}public void delInvestor(Investor i){this.investors.remove(i);}protected void notifyInvestors(int price,String stockName){System.out.println("begin to notify the investors.");for(Investor i:investors){i.update(price,stockName);}};public abstract void setPrice(int price);}把观察者抽象起来
public interface Investor {public void update(int state,String stockName);}实现某个具体的股票:信息发展
public class XXFZStock extends Stock{public String name="300469";public void setPrice(int price){System.out.println("change price.");this.price = price;this.notifyInvestors(price,name);}}实现某个北京的股民
public class BeijingInvestor implements Investor {private String name;public BeijingInvestor(String name){this.name = name;}public void update(int price,String stockName){System.out.println("Beijing Investor " + this.getName() + " know the "+stockName+" stock change to " + price);}public String getName(){return this.name;}}客户端操作模拟北京某股民顶上 300469后,股票价格发生波动
public class Client {public static void main(String[] args){Stock stock = new XXFZStock();stock.addInvestor(new BeijingInvestor("Huangzs"));stock.setPrice(19);stock.setPrice(25);}}