行为型
行为型的模式,当然是拿行为做文章,比如:
- 把很多行为放在一个类内管理
- 抽象行为,使他可以被替换。
- 等等
责任链模式
场景:多个对象都有可能接受并处理请求,而客户端并不确定哪个对象能完成这个请求。
实现:每个对象设置下一个处理对象,如果自己不能处理,则传递下去。
常用实例:拦截器、过滤器、日志(级别)
public abstract class Dealer{
private Dealer dealer;
public void setNext(Dealder dealer){
this.dealer = dealer; }
public void getNext(){
return dealer; }
public abstract boolean deal(){
}
}
public class ConcreteDealer extends Dealer{
@Override
public boolean deal(){
if (getNext()!=null){
System.out.println("go next");
getNext().deal();
}
else{
System.out.println("done");
}
}
}
public class Client{
public static void main(String[] args){
//可以看到链式的组成,对于这几个类是不可知的,他们只专注于处理和传递
ConcreteDealer normalDealer = new ConcreteDealer();
ConcreteDealer advancedDealer = new ConcreteDealer();
ConcreteDealer expertDealer = new ConcreteDealer();
normalDealer.setNext(advancedDealer);
advancedDealer.setNext(expertDealer);
normalDealer.deal();
}
}
命令模式
场景:通常一个对象类包含多种请求,如果有多个类中的多个请求,要组合起来,方便调用。
实现:将请求包装成统一调用方法的命令类,并将对象组合到命令类内。
常用实例:Linux下命令
优缺点:
- 优点:用户体验极好,只需要关注命令类即可。
- 缺点:效率低下,滋生太多命令类
//简化命令类的统一调用函数。call execute都可以
public interface ICMD{
public void call();}
public class OldOrder{
private int orderId;
public void setOrderId(int orderId){
this.orderId = orderId; }
public void getOrderId(int orderId){
return orderId; }
public void sell(){
System.out.println("sell "+getOrderId()); };
public void buy(){
System.out.println("buy "+getOrderId()); };
}
public class CMDSell extends ICMD{
private OldOrder oldOrder;
public CMDSell(OldOrder oldOrder){
this.oldOrder = oldOrder; }
public void call(){
this.oldOrder.sell(); }
}
public class CMDBuy extends ICMD{
private OldOrder oldOrder;
public CMDBuy(OldOrder oldOrder){
this.oldOrder = oldOrder; }
public void call(){
this.oldOrder.buy(); }
}
public class TestDemo{
public static void main(String[] args){
OldOrder oldOrder = new OldOrder();
oldOrder.setOrderId(999);
new CMDBuy(oldOrder).call();
new CMDSell(oldOrder).call();
}
}
解释器模式
场景:一些固定的场景,比如表达式计算(ax^2 + bx+c),使用一个抽象语法树概括起来。
实现:使用终结符(计算单元)、非终结符(运算符号)、环境角色(对计算单元的赋值),通过抽象解释器,完成语法的解释。
常用实例:编译器、数学表达式计算(expression4J)、外挂脚本
优缺点:
- 优点:在生产、制作表达式时非常简单
- 缺点:类膨胀,如果需求一直变化,维护很麻烦
重点:终结符的interpreter得到值;而非终结符的interpreter得到更细的Expression。
//抽象解释器
public interface Expression{
public Object interpreter(Context ctx);
}
//终结符/终结表达式/计算单元
public class TerminalExpression implements Expression{
private String key;
public TerminalExpression(String) key){
this.key = key;
}
//环境,本例中,计算单元的运算结果,就是自己的key在ctx中对应的value
public Object interpreter(Context ctx){
return ctx[key];
}
}
//非终结符/非终结表达式/计算符
// x^2 表达式
public class AddExpression implements Expression{
//加法需要2个表达式;如果是开根号,就只需要一个了
private Expression exp1;
private Expression exp2;
public SqartExpression(Expression exp1,Expression exp2){
this.exp1 = exp1;
this.exp2 = exp2;
}
//需要等两个exp的计算;两个exp可能是终结符,也可能是非终结符。
public Object interpreter(Context ctx){
return exp1.interpreter(ctx) + exp2.interpreter(ctx);
}
}
迭代器模式
场景:提供一种方法,可以顺序访问聚合中的每一个对象,但是又不暴露聚合的其他细节。
实现:将这种访问的方法抽象出来,所有的聚合类继承他即可。
常用实例:JAVA 中的 iterator,其他语言也都有
public interface Iterator{
public boolean hasNext();
public Object Next();
}
public interface Container{
public Iterator getIterator();
}
//具体容器类
public class ConcreteContainer implements Container{
public String[] items = {
"aaa","bbb","ccc"}
public Iterator getIterator(){
return new ConcreteIterator();
}
//内部具体枚举类
private class ConcreteIterator implements Iterator{
private int index;
public boolean hasNext(){
return index< names.length - 1;
}
public Object Next(){
if (hasNext()){
return items[++index];
}
else{
return null;
}
}
}
}
public class IteratorDemo {
public static void main(String[] args) {
ConcreteContainer concreteContainer = new ConcreteContainer();
for(Iterator iter = concreteContainer.getIterator(); iter.hasNext();){
String item = (String)iter.next();
System.out.println("item = " + item);
}
}
}
中介者模式
场景:多个对象之间存在关系,由于对象的数量较多,变得及其复杂,也很难维护、扩展。
实现:创建一个中介者,所有的通信行为,都通过这个中介。将网状通信改变为海星状通信。
常用实例:服务注册中心、网关、MVC(C是中介)
优缺点:
- 优点:解耦,一对多变成了一对一
- 缺点:中介者集成了太多关系,可能变得过于复杂。
//标准场景是聊天室
//一人对多人的聊天发送规则,变成了人和聊天室之间的发送规则
public class ChatRoom{
public static void showMessage(User talker,String msg){
//这里可以作规则,判断两者是好友?黑名单?陌生人?
//这些规则统一在中介者作判断,而对象只负责发送和接收,这就是中介者的意义
System.out.println(talker.getName()+":"+msg);
}
}
public class User{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User(String name){
this.name = name;
}
//这里仅仅演示一下中介模式的作用
public void sendMessage(String message){
ChatRoom.showMessage(this,message);
}
}
备忘录模式
场景:在不破坏对象的前提下,将对象状态在外部保存起来,这样就可以恢复到保存的状态。
实现:
常用实例:ctrl+z、数据备份、游戏存档
//游戏,随着play,状态变化,可以存档,可以读档
public class Game{
private String _state ="begin";
public void play(String s){
_state += s;}
public Memeto save(){
return new Memeto(this._state);
}
public void load(Memeto backup){
this._state = backup.getState();
}
}
//存档Memeto,当然还可以做个存档管理器,这里略了
public class Memeto{
private String _state;
public Memeto(String state){
this._state=state; }
public String getState(){
return this._state;
}
}
观察者模式
场景:一对多,一个对象Subject变化时,通知到其他的关系对象(Observer)。
实现:在Subject中包含一组Observer,有变化时通知。
常用实例:Subscribe/Publish
public class Cat{
private Vector mouses = new Vector();
public void beObserverdBy(Mouse mouse){
mouses.add(mouse);
}
public void roar(){
for (Mouse mouse in mouses){
mouse.runaway();
}
}
}
public class Mouse{
private String name;
public Mouse(String name){
this.name = name }
public void runaway(){
System.out.println(name + ":猫来了,赶紧跑。。。");
}
}
public class Client{
public static void main(String[] args){
Cat tom = new Cat();
tom.beObserverdBy(new Mouse("Little Jerry"));
tom.beObserverdBy(new Mouse("Big Jerry"));
tom.roar();
}
}
状态模式
场景:一个对象在不同状态下表现出不同的逻辑,这导致对象的每个逻辑都需要判断状态。可以理解为“如果有很多if else,考虑下状态模式”
实现:将对象的“状态”抽象出来,不同的状态包含一套处理对象的逻辑。当对象状态变化,整套逻辑跟随改变。
常用实例:订单状态(待付款、待收货、待评价)
比较:有点像命令模式,但是命令模式是命令内包含对象,状态模式是对象内包含模式。
public interface WorkState{
//状态中的处理方法,都是以对象作为参数
public void work(Context context);
public void eat(Context context);
}
public class OnState implements WorkState{
public void work(Context context){
System.out.println("马上干活"+context.anyParams);
}
public void eat(Context context){
System.out.println("忙呢,晚点吃"+context.anyParams);
}
}
public class OffState implements WorkState{
public void work(Context context){
System.out.println("下班了,明天再说"+context.anyParams);
}
public void eat(Context context){
System.out.println("吃吃吃"+context.anyParams);
}
}
public class Context{
private WorkState state=new OnState();
private String anyParams;
public void changeState(WorkState state){
this.state=state;
}
public void change(String param){
anyParams += param;
}
public void work(){
state.work(this);
}
public void eat(){
state.eat(this);
}
}
public class Client{
public static void main(String[] args){
Context context = new Context();
context.work();
context.eat();
context.change(" when state change");
context.changeState(new OffState());
context.work();
context.eat();
}
}
策略模式
场景:一个对象的行为希望在运行时能够动态改变。
实现:将这个行为抽象出来。通过给对象赋予不同的行为实例,达到动态改变行为。
常用实例:桌面开发的事件
优缺点:一个行为代码需要大量策略类去分别实现。
对比:
状态模式:抽象的是状态,将多个行为封装在一个状态类内;
public interface Strategy{
public void Action();
}
public class FightStrategy extends Strategy{
public void Action(){
System.out.println("let's fight");
}
}
public class RunStrategy extends Strategy{
public void Action(){
System.out.println("let's run");
}
}
public class Context{
public Strategy strategy;
public void enemyComing(){
strategy.action();
}
}
public class Client{
public static void main(String[] args){
Context context = new Context();
context.strategy = new FightStrategy();
context.enemyComing();
context.strategy = new RunStrategy();
context.enemyComing();
}
}
模板模式
场景:子类中有很多相同的内容。
实现:可以创建一个父类,包含这些相同的信息,同时把抽象的内容留给子类实现。
常用实例:常见的abstract父子类
对比:
策略模式:策略模式仅抽象了行为;模板模式抽象了整个类。
public abstract class Order{
public abstract void send();
public void create(){
System.out.println("created by form");
send();
}
}
public class SeaOrder extends Order{
public void send(){
System.out.println("send by ship");
}
}
public class AirOrder extends Order{
public void send(){
System.out.println("send by plane");
}
}
public class Client{
public static void main(String[] args){
SeaOrder seaOrder = new SeaOrder();
seaOrder.create();
AirOrder airOrder = new AirOrder();
airOrder.send();
}
}
访问者模式
场景:对象自身结构变化不大,但是对结构中的Element有很多不同且不相关的操作。
实现:将这些Element的操作全部封装到访问者中,通过调用访问者,实现所有对象的操作。
常用实例:
优缺点:
- 优点:单一职责(所有对象的操作都封装到一个访问者)。
- 缺点:访问者根据具体类来区分调用哪个方法。
public abstract class Element{
public abstract void accept(Visitor visitor);
}
public class House extends Element{
private Element[] rooms;
public House(){
rooms = new Element[] {
new BedRoom(),new BookRoom()};
}
public void accept(Visitor visitor){
for (int i = 0; i < rooms.length; i++) {
rooms[i].accept(visitor);
}
visitor.visit(this);
}
}
public class BedRoom extends Element{
public void accept(Visitor visitor){
visitor.visit(this);
}
}
public class BookRoom extends Element{
public void accept(Visitor visitor){
visitor.visit(this);
}
}
public class Visitor{
//所有内容在Visitor统一管理
public void visit(House house){
System.out.println("this is a big house");
}
public void visit(BedRoom bedRoom){
System.out.println("this is a BedRoom");
}
public void visit(BookRoom bookRoom){
System.out.println("this is a BookRoom");
}
}
public class Client{
public static void main(String[] args){
Element house = new House();
//主动邀请访问者
house.accept(new Visitor());
}
}