行为型模式
描述程序运行时复杂的流程控制,涉及算法和对象间的行为控制。
一、模板方法模式 Template Method
定义算法模板,规范了基本构建,将部分算法延迟到子类进行,是的不改变整体结构情况下重新定义算法特定步骤。
抽象类 AbstractClass
- 模板方法:定义算法骨架,按某种顺序调用基本方法。
- 基本方法: 整体算法中的一个步骤。
- 抽象方法:声明由子类实现。
- 具体方法:抽象类实现,子类和集成或重写。
- 钩子方法:抽象类已经实现,包括用于判断逻辑方法和需要子类重写的空方法。
abstract AbstractClass{
void templateMethod(){
specificMethod();
abstractMethod1();
if(Hook1()){
abstractMethod2();
}
}
void specificMethod(){
System.out.println("开始");
}
void abstractMethod1();
void abstractMethod2();
boolean Hook1(){
return true;
}
}
具体子类 ConcreteClass
实现抽象类中的抽象方法和钩子方法。
class ConcreteClass extends AbstractClass{
void abstractMethod1(){
System.out.print("method1");
}
void abstractMethod2(){
System.out.print("method2");
}
boolean Hook1(){
return false;
}
}
客户端 TestTemplate
class TestTemplate {
public static void main(String[] args ){
AbstractClass a=new ConcreteClass();
a.templateMethod();
}
}
二、策略模式 Strategy
定义了一系类算法,并对算法进行封装使得可以相互替换,算法的替换不影响客户的调用。
优点:避免多重判断,减少重复代码。
可以根据不同的时间空间选择不同算法,算法扩展不修改原算法。使用放到环境类中,算法实现放到具体策略类中,二者分离。
缺点:客户需要了解算法使用条件,增加很多策略类。
抽象策略类 Strategy
interface Strategy{
void strateyMethod();
}
具体策略类 ConcreteStrategy
class ConcreteStrategyA{
void strategyMethod(){
System.out.println("strategyA");
}
}
class ConcreteStrategyB{
void strategyMethod(){
System.out.println("strategyB);
}
}
环境类 Context
class Context{
private Strategy strategy;
Strategy getStrategy(){
return strategy;
}
void setStrategy(Strategy strategy){
this.strategy=strategy;
}
void strategyMethod(){
strategy.strategyMethod();
}
}
客户端 StrategyPatternTest
class StrategyPatternTest{
public static void main(String[] args){
Context ct=new Context();
ct.setStrategy(new ConcreteStrategyA());
ct.strategyMethod();
}
}
扩展策略工厂 StrategyFactory
class StrategyFactory{
Map stf=new HashMap<>();
void put(String key,Strategy strategy){
stf.put(key,strategy);
}
Strategy getStrategy(String key){
return stf.get(key);
}
void strategyMethod(String key){
stf.get(key).strategyMethod();
}
}
三、命令模式 Command
将请求封装成对象,是的发出请求的责任和处理请求的责任分离。
优点: 降低耦合度,扩展灵活,可以实现宏命令,方便实现Undo,Redo操作。
缺点:增加大量的命令类,增加复杂性。
抽象命令 Command
abstract Command{
void execute();
}
具体命令 ConcreteCommand
class ConcreteCommand implements Command{
private ReceiverA receiverA;
public ConcreteCommand(){
receiverA=new ReceiverA();
}
void execute(){
receiverA.action();
}
}
命令接收者 Receiver
class Receiver{
void action(){
System.out.println("acionA");
}
}
调用者 invoker
class Invoker{
private Command command;
public Invoker(Command command){
this.command=command;
}
public void setCommand(Command command){
this.command=command;
}
public void call(){
command.execute();
}
}
客户端 TestCommandPattern
class TestCommandPattern{
public static void main(){
Command commandA= new ConcreteCommandA();
Invoker invoker=new Invoker(commandA);
invoker.call();
}
}
命令模式扩展
配合组合模式,构成宏命令模式,也即组合命令模式
class CompositeInvoker implements AbstractCommand{
private ArrayList children =new ArraryList<>();
public void add(AbstractCommand a){
children.add(a);
}
public void remove(AbstractCommand a){
children.remove(a);
}
public AbstractCommand getChild(int i){
return children.get(i);
}
public void execute(){
for(Object obj:children){
obj.execute();
}
}
}
四、责任链(职责链模式) Chain of Responsibility
为了避免请求发送者与多个请求处理着耦合在一起,将多有请求的处理着通过前一个对象的引用而连城一条链。请求发生时沿着链传递,直到处理为止。
抽象处理者角色 Handler
abstract Handler{
private Handler next;
public void setNext(Handler handler){
this.next=handler;
}
public Handler getNext(){
return next;
}
void handlerRequest();
}
具体处理角色 ConcreteHandler
class ConcreteHandlerA implements Handler{
void handlerRequest(String rq){
if("A".equal(rq)) System.out.println("处理");
else{
getNext().handlerRequest(rq);
}
}
}
class ConctreteHandlerB implements Handler{
void handlerRequest(String rq){
if("B".equal(rq))
System.out.println("B");
else{
getNext().handlerRequest(rq);
}
}
}
客户类 Client
创建处理链,并向链头的具体处理者对象提交请求。
publict TestChainofResponsibility{
public static void main(String[] args){
Handler handler=new ConcreteHandlerA();
Handler handlerB=new ConcreteHandlerB();
handler.setNext(HandlerB);
handler.handlerRequest("B");
}
}
模式的扩展
- 纯的职责链模式
- 不纯的职责链模式:一个请求必须被某一个处理者对象接收。接收后两种处理一种自己处理或推给下家。
- 允许出现某一个具体处理者对象在承担部分责任后,将其他责任传给下架的情况。
五、状态模式 State
对有状态的对象,把复杂的判断逻辑提取到不同的状态对象中,允许状态对象在其内部状态改变是改变行为。
环境角色 Context
class Context{
private State state;
Pulic void Context(State state){
this.state=new ConcreteStateA();
}
Public void Handle(){
state.Handle(this);
}
public void setState(State state){
this.state = state;
}
public State getState(){
return state;
}
}
抽象状态类 State
abstract State{
void handle(Context context);
}
具体状态类 ConcreteState
class ConcreteStateA extends State{
void Handle(Context context){
System.out.println("A");
context.setState(new ConcreteStateB());
}
}
class ConcreteStateB extends State{
void handle(Context context){
System.out.println("B");
context.setState(new ConcreteStateA());
}
}
客户端 TestState
class TestState{
public static void(String[] args){
Context ct=new Context();
ct.handle("A");
ct.handle("B");
ct.handle("C");
}
}
状态模式扩展
有些情况可能多个环境共享一组状态,这时候需要引入享元模式,状态放到集合中程序共享。
class ShareContext{
private ShareState state;
private HashMap stateSet =new HashMap<>();
public ShareContext(){
state=new ConcreteState1();
stateSet.put("1",state);
state=new ConcreteState2();
stateSet.put("2",state);
state=getState("1");
}
public void setState(ShareState state){
this.state=state;
}
public ShareState getState(String key){
ShareState s= (ShareState)stateSet.get(key);
return s;
}
public void Handle(){
state.handle(this);
}
}
六、观察者模式
多个对象间存在一对多的依赖关系,当一个对象的状态发生改变是其它对象自动更新,这种模式有时候又称作发布-订阅模式。在软件开发中用的最多的是窗体程序设计中的事件处理,sping 中ApplicationContext 的事件机制也是通过该模式实现的。
优点: 降低了目标与观察者之间的耦合关系。目标与观察者之间建立了一套触发机制。
缺点:目标和观察者之间的医疗没有完全解除,可能导致循环引用。 当观察者对象很多时,通知观察者会花费很多时间,影响效率。
抽象主题 Subject
保存观察者对象的聚集类和增删方法,通知所有观察者。
abstract Subject{
private List observers=new ArraryList<>();
public void add(Observer obs){
if(observers.contains(obs))return;
observers.add(obs);
}
public void remove(Observer obs){
observers.remove(obs);
}
public void notifyObserver();
}
具体主题 ConcreteSubject
class ConcreteSubject extends Subject{
public void notifyObserver(){
for(Observer obs:observers){
obs.response();
}
}
}
抽象观察者 Observer
interface Observer{
void response();
}
具体观察者 ConcreteObserver
class ConcreteObserver1 implements Observer{
void response(){
System.out.println("观察者1");
}
}
class ConcreteObserver2 implements Observer{
void response(){
System.out.println("观察者2");
}
}
客户端 TestObserver
class TestObserver{
public static void main(String[] args){
Subject subject =new ConcreteSubject();
Observer obs1=new ConcreteObserver1();
subject.add(obs1);
Observer obs2= new ConcreteObserver2();
subject.add(obs2);
subject.notifyObserver();
}
}
模式扩展
在java中,通过java.util.Observable类和 java.util.Observer 接口定义观察者模式。
1、Observable类
- 抽象目标类,有一个Vector向量,用于保存需要通知的观察者对象
- void addObserver(Observer o) 添加观察者
- void notifyObservers(Object arg) 调用向量中观察者对象update方法
,越晚加入越先得到通知 - void setChange() 用于设置内部标志位,为真时notifyObservers才会通知观察者。
2、Observer接口
抽象观察者,监视目标的变化。
具体目标观察者
class MdmMapping extends Observable{
public void changeMapping(MdmMap mp){
super.setChanged();
super.notifyObservers(mp);
}
}
观察者
class CacheMapping implements Observer{
public void update(Observable o,Object arg){
MdmMap mdmMap=(MdmMap)arg;
Cache.remove(arg.getKey());
}
}
class DbMapping implements Observer{
public void update(Observable o,Object arg){
MdmMap mdmMap=(MdmMap)arg;
Mappingdb.update(mdmMap);
}
}
调用类
public class MappingTest{
public static void main(String[] args){
MdmMapping mdmMp=new MdmMapping();
Observer cache=new CacheMapping();
Observer db =new DbMapping();
mdmMp.addObserver(cache);
mdmMp.addObserver(db);
MdmMap mp=new MdmMap();
mp.setkey("1");
mp.setvalue("男");
mdmMp.changeMapping(mp);
}
}
七、中介者mediator
定义一个中介对象来封装一系列对象之间的交互
优点:
- 降低对象间耦合,使得对象可以独立复用
- 对象间一对多的关系转变为一对一,提高系统灵活性
抽象中介者 Mediator
定义了注册和转发的接口
abstract class Mediator{
public abstract void register(Colleague colleagur);
public abstract void relay(Colleague cl);
}
具体中介者 ConcreteMediator
class ConcreteMediator extands Mediator{
private List colleagues= new ArrayList<>();
public void register(Colleague colleague){
if(!colleagues.contains(colleague)){
colleagues.add(colleague);
colleague.setMedium(this);
}
}
pulic void relay(Colleague cl){
for(Colleague ob:colleagues){
if(!ob.equals(cl)){
((Colleague)ob).receive();
}
}
}
}
抽象同事类 Colleague
abstract class Colleague{
protected mediator mediator;
public void setMedium(Mediator mediator){
this.mediator=mediator;
}
public abstract void receive();
public abstract void send();
}
具体同事类 ConcreteColleague
class ConcreteColleague1 extends Colleague{
public void receive(){
System.out.println("接收请求");
}
public void send(){
System.out.println("发送请求");
mediator.relay(this);
}
}
class ConcreteColleague2 extends Colleague{
public void receive(){
System.out.println("接收请求");
}
public boid send(){
System.out.println("发送请求");
mediator.relay(this);
}
}
八、迭代器 Iterator
提供一个对象来访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。聚合迭代非常密切,大多数语言在实现聚合类是都提供了迭代类。
- 当需要为聚合对象提供多种遍历方式时。
- 为遍历不同聚合结构提供统一的接口。
- 访问聚合对象而无需暴露内部细节时。
抽象聚合 Aggregate
定义存储、添加、删除聚合对象以及创建迭代器对象接口。
interface Aggregate{
public void add(Object o);
public void remove(Object o);
public Iterator getInterator();
}
具体迭代器 ConcreteAggregate
class ConcreteAggregate implements Aggregate{
private List
抽象迭代器 Iterator
定义访问和遍历聚合元素的接口,通常包括hasNext()、first()、next()等方法。
interface Iterator{
public boolean hasNext();
public Object first();
public Object next();
}
具体迭代器 ConcreteIterator
class ConcreteIterator implements Iterator{
private List
模式的扩展
迭代器常常与组合模式结合起来使用,经常潜藏在组合模式的容器构成类中。
class Composite impelements Component{
private List components= new Arrarylist<>();
public void add(Commponent com){
components.add(com);
}
public void remove(Commponent com){
components.remove(com);
}
public Commponent getChild(int i){
return components.get(i);
}
public void Operation(){
System.out.println("opt");
}
public Iterator getIterator(){
return (new ConcreteIterator(components));
}
}
九、访问者模式 Visitor
将作用于某种数据结构中的各元素操作分离成独立的类,使得在不改变数据机构的前提下添加新的操作,为数据结构中的元素提供各种操作。数据元素和数据操作分离,是行为模式中最复杂的一种模式。
抽象访问者 Visitor
为每个对应元素提供一个访问操作visit(),参数标识了被访问元素
interface Visitor{
void visit(ConcreteElementA element);
void visit(ConcreteElementB element);
}
具体访问者 ConcreteVisitor
class ConcreteVisitorA implements Visitor{
void visitor(ConcreteElementA element){
System.out.println("具体访问者A访问->"+element.operationA());
}
void visitor(ConcreteElementB element){
System.out.println("A->"+element.operationB());
}
}
抽象元素 Element
interface Element{
void accept(Visitor visitor);
}
具体元素 ConcreteElement
class ConcreteElementA implements Element{
void accept(Visitor v){
v.visit(this);
}
String operationA(){
return "ConcreteElementA";
}
}
class ConcreteElementB implements Element{
void accept(Visitor v){
v.visit(this);
}
String operationB(){
return "ConcreteElementB";
}
}
对象结构 ObjectStruct
包含元素角色的容器,提供访问者访问元素
class ObjectStruct {
private List elements=new ArrayList<>();
public void accept(Visitor visitor){
Iterator i=list.iterator();
while(i.hasNext()){
((Elemnet)i.next()).accept(visitor);
}
}
public void add(Element element){
list.add(element);
}
public void remove(Element element){
list.remove(element);
}
}
客户端调用 TestVisitor
public class TestVisitor{
public static void main(String[] args){
ObjectStrut objects=new ObjectStrut();
ConcreteElementA cA=new ConcreteElementA();
COncreteElementB CB=new ConcreteElementB();
objects.add(cA);
objects.add(cB);
Visitor vA=new ConcreteVisitorA();
Visitor vB=new ConcreteVisitorB();
objects.accept(vA);
objects.accept(vB);
}
}
模式扩展
访问这模式使用频率比较高的一种模式,通常与迭代器或组合模式联用。
以组合模式为例(主要具体元素类):
叶子构件 Leaf
class ConcreteLeafElement implements Element{
void accept(Visitor v){
v.visit(this);
}
void operatorLeaf(){
System.out.print("leaf");
}
}
树枝构件Composite
class CompositeElement implements Element{
private List elements=new ArrayList<>();
void accept(Visitor v){
for(Element e:elements){
v.visit(e);
}
}
void operatorComposite(){
System.out.print("Composite");
}
void add(Element e){
elements.add(e);
}
void remove(Element e){
elements.remove(e);
}
Element getChild(int i){
elements.get(i);
}
}
十、备忘录模式 Memento
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要的时能将该对象恢复到原先保存的状态。又叫快照模式。
备忘录Memento
class Memento{
private String state;
public Memento(String state){
this.state=state;
}
public void setState(String state){
this.state=state;
}
public String getState(){
return state
}
}
发起人Originator
记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,可以访问备忘录里的所有信息。
class Originator{
private String state;
public void setState(String state){
this.state=state;
}
public String getState(){
return state;
}
public Memento createMemento(){
return new Memento(state);
}
public void restoreMemento(Memento m){
this.setState(m.getState());
}
}
管理者 Caretaker
class Caretaker{
private Memento memento;
public void setMemento(Memento m){
memento=m;
}
public Memento getMemento(){
return memento;
}
}
客户端 TestMemento
public class TestMemento{
public static void main(String[] args){
Originator otr=new Originator();
Caretaker ctr=new Caretaker();
otr.setState("1");
ctr.setMemento(otr.createMemento());
otr.setState("2");
otr.restoreMemento(ctr.getMemento());
}
}
模式扩展
和原型模式结合使用,可以拥有自备功能,省去了备忘录,主要变化在发起人。
class OriginatorPrototype implements Cloneable{
private String state;
public void setState(String state){
this.state=state;
}
public String getState(){
return state;
}
public OriginatorPrototype createMemento(){
return this.clone();
}
public void restoreMemento(OriginatorPrototype opt){
this.setState(opt.getState());
}
public OriginatorPrototype clone(){
try{
return(OriginatorPrototype) super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
}
return null;
}
}
十一、解释器模式 Interpreter
给分析对象定义一个语言,并定义该语言的文法表示,在设计一个解释器来解释语言中的句子。该模式实现了文法表达式处理的接口,该接口解释一个特定的上下文。
- 优点: 扩展性好,可通过集成改变或扩展语法。 每个表达式都是类似的实现比较容易。
- 缺点:解析器模式中通常使用大量的循环和递归调用,当解释的句子复杂时,运行速度很慢,且调试代码比较麻烦。
解释器模式通常用于对简单语言的编译或分析实例中,为了掌握好他的结构和实现,必须先了解编译原理中的“we文法、句子、语法树”等相关概念。
抽象表达式 Abstract Expression
interface AbstractExpression{
public Object interpret(String info);
}
终结符表达式 Terminal Expression
class TerminalExpressoin implements AbstractExpression{
private Set set=new HashSet();
public boolean interpret(String info){
if(set.contains(info)){
return true;
}
return false;
}
public TerminalExpression(String[] data){
for(int i=0;i
非终结符表达式 Nonterminal Expression
class NonterminalExpression implements AbstractExpression{
private AbstractExpression city;
private AbstractExpression person;
public AndExpression(Expression city,Expression person){
this.city=city;
this.person=person;
}
public boolean interpret(String info){
String s[]=info.split("的");
return city.interpret(s[0])&&persion.interpret([s[1]);
}
}
环境 Context
class Context{
private String[] citys={"韶关","广州"};
private String[] persons={"老人","妇女","儿童"};
private Expression cityPerson;
public Context(){
Expression city=new TerminalExpression(citys);
Expression person=new TerminalExpression(persons);
cityPerson=new AndExpression(city,person);
}
pulic void freeRide(String info){
boolean ok =cityPerson.interpret(info);
if(ok) System.out.println("免费");
else System.out.println("扣费2元");
}
}
客户端 TestInterpret
public class InterpreterPattern{
public static void main(String[] args){
Context bus=new Context();
bus.freeRide("广东的妇女");
bus.freeRide("韶关的年轻人");
}
}
模式扩展
项目开发中,如果要对表达式进行分析计算,java提供了数学公式解析器: Expression4J、Jep等