离之前的设计模式之(二) 创建者模式的编写有一段时间了. 这部分的内容其实早已经写好. 最近整理出来.
另: 1. 虽都尽量详尽. 但是, 近来回看, 发现书中并不是都对. 也许是个人的理解不同.
2. 这部分的内容, 后续会分开详述.
23种设计模式中11种结构类型模式。其分别是策略模式、模版方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式和解释器模式。
策略模式(Strateg Pattern)是一种比较简单的模式,也叫做政策模式(Policy Pattern).其定义如下:
Define a family of algorithms, encapsulate(封装) each one, and make them interchangeable.(定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。)
# Strategy - interface - 抽象策略角色
public interface Strategy{
// 策略模式运算法则
public void doSomething();
}
# ConcreteStrategy - class - 具体策略角色
public class ConcreteStrategy1 implements Strategy{
public void doSomething(){
}
}
public class ConcreteStrategy2 implements Strategy{
public void doSomething(){
}
}
// Context - class - 封装角色
public class Context{
// 抽象策略
priavate Strategy strategy;
// 构造函数设置抽象策略
public Context(Strategy _strategy){
strategy = _strategy;
}
// 封装后的策略方法
public void doAnything(){
strategy.doSomething();
}
}
// Client - class - 场景类
public class Client{
public static void main(String []args){
// 声明一个具体的策略
Strategy strategy = new ConcreteStrategy1();
// 申明上下文 - 并选择策略模式
Context context = new Context(strategy);
// 执行策略
context.doAnything();
}
}
模版方法模式(Template Method Pattern)是如此简单,以至于让你感觉到你已经掌握其精髓了。其定义如下:
Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changeing the algorithm’s structure,(定义一个操作中的算法的框架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。)
AbstractClass
内抽象方法一般有2类,基本方法和抽象方法:基本方法: 基本方法也叫做基本操作,由子类实现的方法,并且在模板方法内被调用。
模版方法: 可以有一个或几个,一般是一个具体方法,实现对基本方法的调度,完成固定的逻辑。
# AbstractClass - abstract class - 模版抽象类
abstract class AbstractClass{
// 基本方法
protected abstract void doSomething();
// 基本方法
protected abstract void doAnything();
// 模版方法
public void templateMethod(){
doSomething();
doAnything();
}
}
# ConcereteClass1 - class - 实现方法
public class ConcereteClass1 extends AbstractClass{
// 基本方法
protected void doSomething(){}
// 基本方法
protected void doAnything(){ }
}
# ConcereteClass2 - class - 实现方法
public class ConcereteClass2 extends AbstractClass{
// 基本方法
protected void doSomething(){}
// 基本方法
protected void doAnything(){ }
}
# Client - class - 客户端操作类
public class Client{
public static void main(String []args){
AbstractClass class1 = new ConcereteClass1();
class1.templateMethod();
AbstractClass class2 = new ConcereteClass2();
class2.templateMethod();
}
}
优点: 封装不变的部分,扩展可变部分。
观察者模式(Observer Pattern)也叫做发布-订阅模式(Publish/Subscribe).它是一个在项目中经常使用的模式,其定义如下:
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.(定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。)
观察者模式主要有2种对象: 观察者和被观察者。
被观察者: Subject类。它必须能够动态的添加后删除观察者。(管理和通知观察者)
观察者: Observer类。接受消息后,进行更新操作。(update)
具体被观察者: ConcreteSubject
具体的观察者: ConcreteObserver
另:观察者模式也长被称为
订阅模式(Publish/Subscribe)
# Observer - interface
public interface Observer{
public void Update();
}
# ConcreteObserver - class
public class ConcreteObserver implements Observer{
public void Update(){}
}
# Subject - class - 被观察者
public abstract class Subject{
// 观察者数组
public Vector obsVector = new Vector();
public void attach(Observer o){
obsVector.add(o);
}
public void detach(Observer o){
obsVector.remove(o);
}
public void notify(){
for(Observer o: obsVector){
o.update();
}
}
}
# ConcreteSubject - class
public class ConcreteSubject extends Subject{
public void doSomething(){
// do something
// 业务逻辑
// 通知
super.notify();
}
}
// Client - 场景类
public class Client{
public static void main(String []args){
// 定义观察者
Observer observer = new ConcreteObserver();
// 定义被观察者
Subject subject = new ConcreteSubject();
// 绑定
subject.attach(subject);
// 被观察者活动 - 并通知观察者
subject.doSomething();
}
}
Q & A
观察者模式和访问着模式的区别?
观察者模式和桥接模式的区别?
A: 耦合度不同,被观察者模式执行事件即需要通知观察者。而桥接模式是随意的进行变化耦合。并且一个是结构类型,一个是操作类型。
迭代器模式(Iterator Pattern)目前已经是一个没落的模式,基本上没人会单独写一个迭代器,除非是产品性质的开发,其定义如下:
Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.(它提供一种方法访问一个容器对象中各个元素,而又不需要暴露该对象的内部细节。)
Aggregate: 抽象容器
ConcreteAggreggate: 具体容器
Iterator: 抽象迭代器
ConcreteIterator: 具体迭代器
# Iterator - interface
public interface Iterator{
// 遍历
public Object next();
// 存在下一个元素
public boolean hasNext();
// 删除当前指向
public boolean remove();
}
public class ConcreteIterator implements Iterator{
private Vector vector = new Vector();
public int cursor = 0;
public ConcreteIterator(Vector _vector){
this.vector = _vector;
}
public boolean hasNext(){
if(this.cursor == this.vector.size){
return false;
}else{
return true;
}
}
public Object next(){
Object result = null;
if(this.hasNext()){
result = this.vector.get(this.cursor++);
}else{
result = null;
}
return result;
}
public boolean remove(){
this.vector.remove(this.cursor);
return true;
}
}
# Aggregate
public interface Aggregate{
//add
public void add(Object object);
//remove
public void remove(Object object);
//foreach
public Iterator iterator();
}
# ConcreteAggregate
pubic class ConcreteAggregate implements Aggregate{
private Vector = new Vector();
public void add(Object object){
this.Vector.add(object);
}
public void remove(Object object){
this.remove(object);
}
public Iterator iterator(){
return new ConcreteIterator(this.vector);
}
}
# Client
public class Client{
public static void main(String []args){
Aggregate agg = new ConcreteAggregate();
agg.add("1");
agg.add("8");
// Iterator 遍历
Iterator ietrator = agg.iterator();
while(iterator.hasNext()){
Object o = iterator.next();
}
}
}
迭代器已经融入我们开发的常用数据结构,无须自己实现了。但是基本原理需要进行掌握。
另: 在边删边迭代数组时,部分项会因为下标上升而无法扫描。这时,不要使用
for循环
,需要使用Iterator
的迭代器进行遍历扫描。还有,需要掌握
Vector
这种数据类型的使用和基本原理。
责任链模式的定义如下:
Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request alonge the chain util an object handles it.(使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象形成一条链,并沿着这条链传递该请求,直到有对象处理它为止。)
# Handler
public abstract class Hander{
private Hander nextHandler;
public void setNext(Handler _handler){
nextHandler = _handler;
}
//public final Response handlerMessage(int level){
public final void handlerMessage(int level){
if(level == getLevel()){
echo();
}else if(null != this.nextHandler){
this.nextHandler.handlerMessage(level);
}else{
// 自行处理,也可以什么都不做
}
}
// 级别管理
private int level;
public void setLevel(int level){
this.level = level;
}
public int getLevel(){
return level;
}
// 当执行任务时输出
public abstract void echo();
}
# ConcreteHandler1
public class ConcreteHandler1 extends Hander{
public abstract void echo(){
System.out.println("ConcreteHandler1"+this.getLevel());
}
}
# ConcreteHandler2
public class ConcreteHandler2 extends Hander{
public abstract void echo(){
System.out.println("ConcreteHandler2"+this.getLevel());
}
}
# ConcreteHandler3
public class ConcreteHandler3 extends Hander{
public abstract void echo(){
System.out.println("ConcreteHandler3"+this.getLevel());
}
}
# Client
public class Client{
public static void main(String []args){
Handler handler1 = new ConcreteHandler1();
handler1.setLevel(1);
Handler handler2 = new ConcreteHandler2();
handler2.setLevel(2);
Handler handler3 = new ConcreteHandler3();
handler3.setLevel(3);
handler1.setNext(handler2);
handler2.setNext(handler3);
// test1
handler1.handlerMessage(3);
// test2
handler1.handlerMessage(1);
// test3
handler1.handlerMessage(9);
}
}
责任链模式,主要是使用了链式结构。乍一看和组合模型内的自己包含自己的结构优点类似。但是组合模式更多的是用于结构维护,多数是树形结构。责任链模式的下家在多数情况下只有一个,主要维护的是单链式的结构。
命令模式是一个高内聚的模式,其定义为:
Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.(将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者纪录请求日志,可以提供命令的撤销和恢复功能。)
# Receiver
public abstract class Receiver{
public abstract void doSomething();
}
# ConcreteReceiver1
public ConcreteReceiver1 extends Receiver{
public void doSomething(){}
}
# ConcreteReceiver2
public ConcreteReceiver2 extends Receiver{
public void doSomething(){}
}
# Command
public abstract class Command{
private Receiver receiver;
public Command(Receiver receiver){
this.receiver = receiver;
}
public abstract void execute();
}
# ConcreteCommand
public class ConcreteCommand{
public ConcreteCommand(Receiver receiver){
super(receiver);
}
public void execute(){
this.receiver.doSomething();
}
}
public class Invoker{
private Command command;
public void setCommand(Command command){
this.command = command;
}
public void action(){
this.command.execute();
}
}
# Client - class
public class Client{
public static void main(String []args){
Receiver receiver1 = new ConcreteReceiver1();
Command command = new ConcreteCommand(receiver1);
Invoker invoker = new Invoker();
invoker.setCommnad(command);
invoker.action();
}
}
将命令调用者与命令执行者解耦。
备忘录模式(Memento Patten)提供一种弥补真实世界缺陷的方法,让"后悔药"在程序的世界中真实可行。
Without voilating encapsulation, capture and externalize an object’s internal state so that the object can be restored to this state later.
(在不破坏封装的前提下,捕获一个对象的内部状态,并且在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。)
Originator: 发起人角色
Memento: 备忘录角色
Caretaker: 备忘录管理员角色
# Memento - class
public 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;
}
}
# Orginator
public class Orginator{
private String state = "";
public void setState(String state){
this.state = state;
}
public String getState(){
return state;
}
public Memento createMemento(){
return new Mementor(state);
}
public Memento restoreMemento(Memento memento){
this.state = memento.getState();
}
}
# Caretaker
public class Caretaker{
private Memento memento;
public void setMemento(Memento memento){
this.memento = memento;
}
public Memento getMemento(){
return memento;
}
}
# Client
public class Client{
public static void main(String []args){
// 创建发起者
Orginator originrator = new Orginator();
originrator.setState("hello");
// 创建保管人
Caretaker caretaker = new Caretaker();
// 备份状态
caretaker.setMemento(originrator.createMemento);
// 改变状态
originrator.setState("goodBye");
// 回滚状态
originrator.restoreMemento(caretaker.getMemento());
}
}
Q1: 备忘录模式 与 数据库事务RollBack? 数据库快照的思想
什么是状态模式,其定义下如下:
Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.(当一个对象内在的状态改变时允许其行为改变,这个对象看起来像改变了其类。)
State: 抽象状态角色
ConcreteState: 具体状态角色
Context: 环境角色
# State
public abstract class State{
// 提供环境角色 提供子类访问
protected Context context;
public void setContext(Context _context){
this.context = _context;
}
public abstract void handle1();
public abstract void handle2();
}
# ConcreteState
public class ConcreteState1 extends State{
public void handle1(){}
public abstract void handle2(){
// 设置当前状态为状态2
super.context.setCurrentState(Context.STATE2);
// 过度到State2状态,由Context实现
super.context.handle2();
}
}
# ConcreteState
public class ConcreteState2 extends State{
public void handle1(){
// 设置当前状态为状态1
super.context.setCurrentState(Context.STATE1);
// 过度到State2状态,由Context实现
super.context.handle1();
}
public abstract void handle2(){}
}
public class Context{
//定义状态
public final static State STATE1 = new ConcreteState1();
public final static State STATE2 = new ConcreteState1();
private State currentState;
public void setCurrentState(State _state){
this.currentState = _state;
// 切换状态
this.currentState.setContext(this);
}
// 行为委托
public void handle1(){
this.currentState.handle1();
}
// 行为委托
public void handle2(){
this.currentState.handle2();
}
}
public class Client{
public static void main(String []args){
Context context = new Context();
context.setCurrentSate(new ConcreteState1());
// 行为执行
context.handle1();
context.handle2();
}
}
说实话,这章的结构让我觉得优点云里雾里的感觉。对于此章用例,我持怀疑的态度。
另: 状态模式对于类之间的耦合度应当是极高。
访问者模式(Visitor Pattern)是一个相对简单的模式,
其定义如下: Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.(封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的数据。)
Visitor - 抽象访问者
ConcreteVisitor - 具体访问者
Element - 抽象元素
ConcreteElement - 具体元素
Client - 客户端类
# Element - class
public abstract class Element{
// 定义业务逻辑
public abstract void doSomething();
// 允许谁来访问
public abstract void accept(Visitor visitor);
}
# ConcreteElement - class
public class ConcreteElement1 extends Element{
// 定义业务逻辑
public abstract void doSomething(){}
// 允许谁来访问
public abstract void accept(IVisitor visitor){
visitor.visit(this);
}
}
# IVisitor - interface
public interface IVisitor{
public void accept(Element element);
}
#
public ConcreteVisitor implements IVisitor{
public void accept(Element element){
if(element instance of ConcreteElement1){
// ConcreteElement1
}else if(element instance of ConcreteElement2){
// ConcreteElement2
}else{
// do something
}
}
}
# Client - class
public class Client {
public static void main(String []args){
Element element1 = new ConcreteElement1();
IVisitor visitor = new ConcreteVisitor();
element1.accept(visitor);
}
}
个人理解: 访问者模式更像是打开被访问者的内部,一个特殊的打开的接口。但是访问者通常逻辑较为固定,并且多和被访问者多自身的实现类型相关,难以扩展。
中介者模式的定义为:
Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.(用一个中介对象封装一系列对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散,而且可以独立地改变它们之间的交互。)
Mediator 抽象中介者
ConcreteMediator 实体中介者
Colleague 同事角色。同事角色有2种方法:自发行为(Self-Method)与依赖方法(Dependent Method)。前者角色自身可以实现,后者需要通过中介者进行耦合。
# Mediator - abstract class
public abstract class Mediator{
// 定义同事类(注意此处可能使用接口更加适合)
protected ConcreteColleague1 colleague1;
protected ConcreteColleague2 colleague2;
// Getter/Setter
public ConcreteColleague1 getColleague1(){
return colleague1;
}
public void setColleague1(ConcreteColleague1 colleague1){
this.colleague1 = colleague1;
}
public abstract void doSomething1();
public abstract void doSomething2();
}
# 具体中介者
public class ConcreteMediator extends Mediator{
public abstract void doSomething1(){
// 多个对象类中操作的合集
colleague1.doSomething();
colleague2.doSomething();
}
public abstract void doSomething2(){
colleague1.doSomething();
colleague2.doSomething();
}
}
# 抽象同事类
public absract class Colleague{
protected Mediator mediator;
public Colleague(Mediator mediator){
this.mediator = mediator;
}
}
# 具体抽象类
public class ConcreteColleague1 extends Colleague{
public ConcreteColleague(Mediator mediator){
super(mediator);
}
// 自身私有方法
public void selfMethod(){
}
// 依赖方法
public void depMethod(){
mediator.doSomething1();
}
}
public class ConcreteColleague2 extends Colleague{
public ConcreteColleague(Mediator mediator){
super(mediator);
}
// 自身私有方法
public void selfMethod(){
}
// 依赖方法
public void depMethod(){
mediator.doSomething2();
}
}
# Client - class
public class Client{
public static void main(String []args){
// 定义中介者
Mediator mediator = new ConcreteMediator();
// 定义同事类
Colleague colleague1 = new ConcreteColleague1(mediator);
// 私有方法
colleague1.selfMethod();
// 执行依赖方法
colleague1.depMethod();
}
}
# Caretaker
Q & A
Q: 中介者模式和代理模式的区别?
A: 代理是单个角色,中介整合的是多个角色。代理是相当于将原对象封装一层,不对于原对象进行直接访问。中介相当于是抽象出多个类中需要相互处理的部分,托管到中介者中,由中介者进行管理复杂的类间结构,其余类与中介者直接关联即可。
个人理解: 中介模式的本意就是将网状的复杂的实体类之间的关系简化为各个部分与中介者之间的关系。但是中介模式不是适合所有的中介模式。
中介模式最主要的作用就是解耦。解除复杂的关系,统一由中介者帮助维护和处理。(带参数的方法如何维护?)
解释器模式(Interpreter Pattern)是一种按照规定语法进行解析的方案,在现在项目中使用较少,其定义如下:
Given a language, define a representation for its grammar alonge with an interpreter that uses the representatin to interpret sentences in the language.(给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。)
Expression: 抽象解释器
TerminalExpression: 终结符表达式
NonterminalExpression: 非终结符表达式
Context: 环境角色
# Expression
public abstract Expression{
// 解析任务
public abstract Object interpreter(Context ctx);
}
public class TerminalExpression extends Expression{
// 通常终结符表达式只有一个,但是有多个对象
public Object interpreter(Context ctx){
return null;
}
}
public class NonterminalExpression extends Expression{
// 每个非终结符表达式都会对其他表达式产生依赖
public NonterminalExpression(Expression ..expression){
}
// 进行解析
public Object interpreter(Context ctx){
return null;
}
}
public class Client{
public static void main(String []args){
Context ctx = new Context();
// 通常定义一个语法容器 容纳一个具体的表达式 通常为 ListArray、LinkedList、Stack等类型
Stack stack = new Stack();
for(;;){
// 进行语法判断,产生递归调用
}
//产生一个完整的语法树 由各个具体的语法分析进行解析
Expression exp = stack.pop();
// 具体元素进入场景
exp.interpreter(ctx);
}
}
个人理解: 该模式在开发中,使用不多。但是如果需要做规则分析,和公式解析的使用,可以使用该模式。