装饰模式主要用于为某个现有的类添加某个功能,扩展现有的类的功能一般有两种方式,一种是通过继承,一种是通过对象组合,第一种是比较强行植入的方式,而第二种就比较灵活,其实设计模式中有很多都可以看到这种方式的影子,它本质上是通过植入具有相同接口的对象,植入哪个对象就由哪个对象来实现这个功能,通过需要达到的效果植入不同的对象,被植入对象的框架都保持原样,这就达到了复用的效果。

回到装饰模式,使用装饰模式的目的在于透明,动态地为某个类扩展某个功能,这里的透明指的是所有对原对象的装饰对于被装饰的对象来说是不知情的,对原对象一点都不会产生影响。
装饰模式还有个用途就是可以用于控制功能的访问权限问题。

public abstract class AbsComponent {
public abstract void OriginalComponent();
}
public class ConcreComponent extends AbsComponent {
public void OriginalComponent() {
System.out.println("This is from OriginalComponent");
}
}
public abstract class AbsDecorator extends AbsComponent{
protected AbsComponent component = null;
public AbsDecorator(AbsComponent conponent) {
this.component = conponent;
}
public void OriginalComponent() {
component.OriginalComponent();
}
}
public class ConcreDecorator extends AbsDecorator {
public ConcreDecorator(AbsComponent conponent) {
super(conponent);
}
public void selfFunction() {
System.out.println("extend the original function with self function");
super.component.OriginalComponent();
}
}
public class Client {

public static void main(String args[]) {
AbsComponent component = new ConcreComponent();
ConcreDecorator decorator = new ConcreDecorator(component);
decorator.selfFunction();
}
}

组合模式用于让客户端不再区分操作的是组合对象还是叶子对象,而是以一个统一的方式来操作。它的关键在于使用一个抽象的组件,来代表组合对象和叶子对象。这样客户就可以不用区分到底操作的是组合对象还是叶子对象了,只需要把他们全部当作组件对象进行统一操作就可以了。

public abstract class Component {
public String name = null;

public Component(String name) {
this.name = name;
}

public void addChild(Component component) {
throw new UnsupportedOperationException();
}

public void removeChild(Component component) {
throw new UnsupportedOperationException();
}

public Component getComponent(int index) {
throw new UnsupportedOperationException();
}

public abstract String getName();

}
import java.awt.List;
import java.util.ArrayList;
public class Compositive extends Component{
private ArrayList<Component> componentlist = new ArrayList<Component>();
public Compositive(String name) {
super(name);
}

public String getName() {
return super.name;
}

public void addChild(Component component) {
if(component!= null) {
componentlist.add(component);
}
}

public void removeChild(Component component) {
if(componentlist!= null && componentlist.contains(component)) {
componentlist.remove(component);
}
}

public Component getComponent(int index) {
if(componentlist != null) {
return componentlist.get(index);
}
return null;
}
}
public class Leaf extends Component {
public Leaf(String name) {
super(name);
}
public String getName() {
return super.name;
}
}
public class Client {
public static void main(String args[]) {
Component component1 = new Compositive("组合1");
Component component2 = new Compositive("组合2");
Component component3 = new Compositive("组合3");
Component component4 = new Compositive("组合4");
Component component5 = new Compositive("组合5");

Component leaf1 = new Compositive("根节点1");
Component leaf2 = new Compositive("根节点2");
Component leaf3 = new Compositive("根节点3");
Component leaf4 = new Compositive("根节点4");
Component leaf5 = new Compositive("根节点5");

component1.addChild(component2);
component1.addChild(component3);
component1.addChild(component4);
component1.addChild(component5);
component2.addChild(leaf1);
component2.addChild(leaf2);
component3.addChild(leaf3);
component4.addChild(leaf4);
component4.addChild(leaf5);
}
}

简介:

之前讲过模板方法,它的好处就是可以保持模板整体固定,只是特定步骤通过子类的复写,从而实现对整个模板的影响。
这里要介绍的策略方法和模板方法有类似地方,但是也存在较大的区别,这是废话,不然就不用多个策略模式了,
那么什么是策略模式呢?策略模式就是把一系列的算法从具体的业务处理中独立封装起来,把它们实现成为独立的算法类,使得他们可以相互替换,通过这种方式来实现客户和算法之间的解耦。
它的具体思路是通过一个持有算法的上下文对象,来封装一系列算法,这个对象并不负责决定具体选用哪个算法,而把算法选择的工作交给了客户,客户选择好具体的算法后设置到上下文对象中让上下文对象持有客户选择的算法,当客户通知上下文对象执行功能的时候,上下文对象则转调具体的算法,这样具体的算法和直接使用算法的客户就能够实现分离了。
在策略模式中上下文对象就是各个策略算法的公共类,可以在这里面存放各个算法所公用的数据以及所需要的公共方法。

其实说到公共方法这里有三种组织方式:
在上下文当中实现公共功能,让所有具体的策略算法回调这些方法。
将策略的接口改成抽象类,然后在其中实现具体算法的公共功能
为所有的策略算法定义一个抽象父类,让这个父类去实现策略的接口,然后在这个父类中实现公共的功能。

策略模式的使用场合:

在出现很多仅仅是行为有差别的相关类的情况下,可以使用策略模式来在这些行为之间动态切换。
出现同一个算法,有很多不同实现的情况下,可以使用策略模式来吧这些不同的实现,实现成为一个算法的类层次。
需要封装算法中存在和算法相关数据的情况下,可以使用策略模式来避免暴露这些跟算法相关的数据结构。

public interface StragryInterface {
public void stragryMethod();
}
public abstract class AbstractStragry implements StragryInterface {
protected void commonMethodOne() {
System.out.println("This is common Method One");
}

protected void commonMethodTwo() {
System.out.println("This is common Method Two");
}

public abstract void stepOne();
public abstract void stepTwo();
public void stragryMethod() {
stepOne();
stepTwo();
}
}
public class ConcreStragryOne extends AbstractStragry {
public void stepOne() {
System.out.println("This is from ConcreStragryOne");
super.commonMethodOne();
}
@Override
public void stepTwo() {
System.out.println("This is from ConcreStragryOne");
super.commonMethodTwo();
}
}
public class ConcreStragryTwo extends AbstractStragry {
public void stepOne() {
System.out.println("This is from ConcreStragryTwo");
super.commonMethodOne();
}
@Override
public void stepTwo() {
System.out.println("This is from ConcreStragryTwo");
super.commonMethodTwo();
}
}
public class Context {

private AbstractStragry mStragry = null;
public Context(AbstractStragry stragrey) {
mStragry = stragrey;
}
public void callStragrey() {
mStragry.stragryMethod();
}

public void setStragrey(AbstractStragry stragrey) {
mStragry = stragrey;
}
}
public class Client {

public static void main(String[] args) {
AbstractStragry stragryOne = new ConcreStragryOne();
AbstractStragry stragryTwo = new ConcreStragryTwo();
Context contextOne = new Context(stragryOne);
contextOne.callStragrey();

contextOne.setStragrey(stragryTwo);
contextOne.callStragrey();
}
}

概述

在状态模式中,状态通常指的是对象实例的某个属性值,而行为指的就是对象的方法。
它通过把状态和状态对应的行为分离开来,把所有与一个特定的状态相关的行为都放在一个对象中,通过维护状态的变化,来调用不同状态对应的方法。使得应用程序在控制的时候只需要关心状态的转换,而不用关心这个状态对应的真正处理。简而言之就是状态决定行为。
在状态模式中,上下文是持有状态的对象,但是上下文自己并不处理和状态相关的行为,而是把处理状态的功能委托给了状态对应的对象处理。一般而言上下文持有一个状态对象,以及状态维护,状态处理类负责状态的改变。当然状态的改变也可以放在上下文中
在具体的状态类处理类中经常需要获取上下文自身的数据,以及回调上下文的方法,因此通常情况下会将上下文作为一个参数传递给具体的状态处理类。
客户端一般只和上下文交互,并且一般不负责运行期间状态的维护,也不负责决定后续到底使用哪个具体的状态处理对象。

在状态模式中,状态的维护指的是维护状态的数据,给状态设置不同的状态值,而状态的转换指的是根据状态的变化选择不同的状态处理对象。

状态维护和转换控制

一般通常有如下几个地方可以进行状态的维护和转换控制:
1.上下文中,因为状态本身通常被实现为上下文对象的状态,因此可以在上下文中进行状态的维护和状态的转换。这种情况一般适用于状态转换规则相对固定,不需要进行什么扩展。
2.状态的处理类中:当每个状态处理对象处理完自身状态所对应的功能后,可以根据需要指定后继状态,一遍让应用能够正确处理后续的请求。
这种情况适用于当前状态取决于前一个状态动态处理的结果,或者是依赖于外部数据的情况
3.使用数据库或者文件:
这种方式可以通过在程序中查询数据库中的数据来得到状态编码,然后根据状态编码来创建出相应的状态对象,在委托相应的状态对象进行功能处理。
使用这种方式的话,还可以通过将状态码和状态处理类名存放到配置文件中,这样就可以直接通过配置文件获取到状态处理类的类名,再通过反射机制创建出处理类,这种方式的好处就在于上下文中状态转换维护的代码就相对固定。
状态扩展
状态模式的扩展只需要新增一个实现状态处理的公共接口实现类,然后在进行状态维护的地方,设置状态变化到这个新的状态即可。

public interface State {
public void someOperation();
}
public class ConcreStateOne implements State{   
private Context mContext = null;
public ConcreStateOne(Context context) {
mContext = context;
}
public void someOperation() {
System.out.println("This is from ConcreStateOne");
mContext.changeStateCode(2);
}
}
public class ConcreStateTwo implements State{
private Context mContext = null;
public ConcreStateTwo(Context context) {
mContext = context;
}
public void someOperation() {
System.out.println("This is from ConcreStateTwo");
mContext.changeStateCode(1);
}
}
public class Context {
private State mState = null;
private int stateCode = -1;
public void changeStateCode(int stateCode) {
this.stateCode = stateCode;
}
private void createState() {
if(stateCode == -1 || stateCode == 1) {
mState = new ConcreStateOne(this);
}else if(stateCode == 2) {
mState = new ConcreStateTwo(this);
}
}
public void doSomeOperationInstate() {
createState();
if(mState != null) {
mState.someOperation();
}
}
}
public class Client {
public static void main(String[] args) {
Context mContext = new Context();
mContext.doSomeOperationInstate();
mContext.doSomeOperationInstate();
mContext.doSomeOperationInstate();
mContext.doSomeOperationInstate();
mContext.doSomeOperationInstate();
mContext.doSomeOperationInstate();
mContext.doSomeOperationInstate();
mContext.doSomeOperationInstate();
mContext.doSomeOperationInstate();
}
}

概述

模板方法是通过定义一个算法骨架,而将算法中的步骤延迟到子类,这样子类就可以复写这些步骤的实现来实现特定的算法。
同时由于父类定义好了算法的步骤,只是在某几个固定的点才回调用到被之类实现的方法,所以也就只允许在几个点类扩展功能。
从实现角度来看:模板方法主要通过制定模板,把算法步骤固定下来。至于谁来实现,模板可以自己提供,也可以子类去实现,还可以通过回调让其他类来实现。

在模板里面包含如下几类方法:

  • 模板方法:用于定义算法的框架。
  • 具体方法:在模板中直接实现某些步骤的方法,通常这些步骤的实现算法是固定的,而且是不怎么变化的,因此可以将其当做公共功能实现在模板中,如果不需要为子类提供访问这些方法的话,可以将这些方法定义为privete,如果是提供给子类访问的,可以吧这些方法定义为protected final,从而避免子类对这些方法的复写。
  • 原语操作,在模板中定义的抽象操作,通常是模板方法需要调用的操作,而且这些操作在父类中还没有办法确定下来。需要子类来实现真正的方法。
  • 回调方法:通过回调机制来调用其他类中的方法。
  • 工厂方法,在模板方法中如果需要得到某些对象的实例的话,可以考虑通过工厂方法来获取,把具体的创建对象延迟到子类中去。
public abstract class TempleClass {
private void stepOne() {
System.out.println("This is step One from TempleClass");
}
protected void stepTwo() {
System.out.println("This is step Two will be call by Child Temple with Overwrite");
}
protected final void stepThree() {
System.out.println("This is step Three will be call by Child Temple without Overwrite");
}
protected abstract void TempleMethodOne();
protected abstract void TempleMethodTwo();
public void temple(HookCallBack callback){
stepOne();
stepTwo();
stepThree();
TempleMethodOne();
TempleMethodTwo();
callback.methodFromHook();
}
}
public interface HookCallBack {
public void methodFromHook();
}
public class ChildTempleClassOne extends TempleClass {
protected void stepTwo() {
System.out.println("This is from ChildTempleClassOne");
}

protected void TempleMethodOne() {
System.out.println("This is from ChildTempleClassOne TempleMethodOne");
}
protected void TempleMethodTwo() {
System.out.println("This is from ChildTempleClassOne TempleMethodTwo");
}
}
public class ChildTempleClassTwo extends TempleClass {
protected void stepTwo() {
System.out.println("This is from ChildTempleClassTwo");
}
protected void TempleMethodOne() {
System.out.println("This is from ChildTempleClassTwo TempleMethodOne");
}
protected void TempleMethodTwo() {
System.out.println("This is from ChildTempleClassTwo TempleMethodTwo");
}
}
public class Client {

public static void main(String args[]){
TempleClass temple1 = new ChildTempleClassOne();
TempleClass temple2 = new ChildTempleClassTwo();
temple1.temple(new HookCallBack() {
public void methodFromHook() {
System.out.println("This is from HookCallBack from temple1");
}
});

temple2.temple(new HookCallBack() {
public void methodFromHook() {
System.out.println("This is from HookCallBack from temple2");
}
});
}
}

概述

桥接模式适合于存在两个维度变化的情形。这种情况下一个维度的变化往往会引起另一个维度的变化。这样扩展起来变得十分困难。桥接模式的主要思路就是将两个维度的变化独立开来,不会产生相互影响。
抽象部分的接口一般维护一个现实部分的对象引用,抽象对象里面的方法,需要调用实现部分的对象来完成。这个对象中的方法通常都是和具体的业务相关的方法。

扩展抽象方法通常在这些对象中定义和业务相关的方法,这些方法会使用抽象部分接口中的方法。也可能需要调用实现部分对象来完成。

实现部分的接口,提供基本操作,抽象部分定义的一般都是基于这些基本操作的业务方法。
实现部分的接口一般有如下几种实现方式:

  1. 由客户端负责创建,并在创建抽象部分接口的时候作为参数设置到抽象部分的对象中去。
  2. 可以在抽象部分对象构建的时候,由抽象部分的对象自己来创建对应的现实部分的对象。
  3. 可以使用抽象工厂或者简单工厂来选择并创建具体的实现部分。
  4. 可以在抽象部分选择并创建一个默认的实现部分,子类可以根据具体的需要改变这个实现。

何时使用桥接模式:

不希望抽象和实现部分采用固定的绑定关系的时候,可以采用桥接模式把抽象和实现部分分开,然后在程序运行期间动态得设置抽象部分需要用到的具体实现,还可以动态地切换具体的实现。
如果希望实现部分的修改不会对客户端产生影响,可以采用桥接模式,由于客户是面向抽象的接口在运行,实现部分的修改可以独立于抽象部分,而不会对客户端产生影响。

public interface Implementor {
public void someOperator();
}
public class ConcreImplementor1 implements Implementor {
public void someOperator() {
System.out.println("This is someOperator from ConcreImplementor1");
}
}
public class ConcreImplementor2 implements Implementor {
public void someOperator() {
System.out.println("This is someOperator from ConcreImplementor2");
}
}
public abstract class AbstractPart {
private Implementor mImplementor = null;
public AbstractPart(Implementor imp) {
this.mImplementor = imp;
}
public void otherOperator(){
this.mImplementor.someOperator();
}
}
public class RedefineAbstract extends AbstractPart {
public RedefineAbstract(Implementor imp) {
super(imp);
}

public void othersOperator() {
System.out.println("Add some pre Operation");
super.otherOperator();
}
}
public class Client {
public static void main(String[] args) {
Implementor imp1 = new ConcreImplementor1();
RedefineAbstract abstract1 = new RedefineAbstract(imp1);
abstract1.othersOperator();

Implementor imp2 = new ConcreImplementor2();
RedefineAbstract abstract2 = new RedefineAbstract(imp2);
abstract2.othersOperator();
}
}

应用场景:

建造者模式细分起来有两个用途
1.将整体构建过程和具体部件的构建过程分离,达到使用同一个构建过程创建出不同表示的效果。
就比如按照同一个装修方案装修你刚买的房子,虽然设计布局都一样,这里摆个电视,这里摆个沙发,但是你定制的家具的风格不一样的话,即使使用同一个装修方案,装修出来的房间也大不相同。
2.在构造方法需要大量参数或者构造带约束规则的场景
我们知道构造方法的参数一般是有限的,但是如果一个类的成员变量较多,并且并不是每个都需要设置的时候,这种情况就比较灵活,通过建造者模式只对需要设置的成员变量进行设置,对于不需要的则使用默认的就可以,这时候的构造者模式就相当于一个灵活的构造方法。

建造者模式类图:

从上面类图可以看出主要有三个部分

  • 产品类:是我们目标创建对象,一般是过程复杂的对象
  • 建造者:定义创建产品各个部分的操作。负责部件构造和部件装配。
    在建造者中包含两个部分,一部分创建部件对象,一部分组装部件。
  • 指导者:规定如何将builder构建出的部件组装起来。它只负责整体的构建算法,并不负责每部分的具体创建过程。
    指导者是较为固定的部分。一般在指导者中有较为复杂的算法,在执行过程中根据需要调用建造者创建出需要的部件。
    整个过程如下所示:
    指导者运行构建算法,在算法运行到某个阶段需要某个部件的时候调用构造者创建所需的部件,这时候可以将参数传递给建造者供构建过程使用,建造者完成所需部件的构建后,返回构建的部件,指导者继续执行构建算法,直到最后将这些部件给装配起来。
  1. 第一种用法:

抽象Builder:可以是抽象类或者接口

public interface AbsBuilder {
void buildwheel(String wheelType);
void buildCarBody(String bodyType);
void buildCarDoor(String doorType);
}

具体Builder

public class ConcreBuilder implements AbsBuilder {
private ProductCar mCar = null;
public ConcreBuilder() {
mCar = new ProductCar();
}
public void buildwheel(String wheelType) {
mCar.setWheel(wheelType);
}
public void buildCarBody(String bodyType) {
mCar.setCarBody(bodyType);
}
public void buildCarDoor(String doorType) {
mCar.setCarDoor(doorType);
}
public void resultCar() {
if(mCar == null) {
return;
}
System.out.println("车轮:"+mCar.getWheel());
System.out.println("车门:"+mCar.getCarDoor());
System.out.println("车身:"+mCar.getCarBody());
}
}

产品类

public class ProductCar {

private String wheel = null;
private String carBody = null;
private String carDoor = null;

public String getWheel() {
return wheel;
}
public void setWheel(String wheel) {
this.wheel = wheel;
}
public String getCarBody() {
return carBody;
}
public void setCarBody(String carBody) {
this.carBody = carBody;
}
public String getCarDoor() {
return carDoor;
}
public void setCarDoor(String carDoor) {
this.carDoor = carDoor;
}
}

Director类

public class Director {
private ConcreBuilder builder = null;
public Director(ConcreBuilder builder) {
this.builder = builder;
}
public void makeCarProduct() {
builder.buildCarBody("红色的车身");
builder.buildCarDoor("白色的车门");
builder.buildwheel("五个车轮");
builder.resultCar();
}
}

Client类

public class Client {
public static void main(String args[]) {
ConcreBuilder builder = new ConcreBuilder();
Director direcor = new Director(builder);
direcor.makeCarProduct();
}
}

第二种用法:

public class ProductCar {
private int mCarwheelNum = 0;
private int mCarDoorNum = 0;
private String mCarColor = null;

/*构建产品*/
public ProductCar(CarBuilder carBuilder) {
mCarColor = carBuilder.getColor();
mCarwheelNum = carBuilder.getWheelNum();
mCarDoorNum = carBuilder.getDoorNum();
}

public void run() {
System.out.println("一辆"+mCarColor+"色,"+mCarwheelNum+"轮,"+mCarDoorNum+"个门的车跑起来了");
}

/*可以在set方法中以及build方法中添加限制条件*/
public static class CarBuilder {
/*可以设置的属性*/
private int wheelNum = 0;
private int doorNum = 0;
private String color = null;
/*这里可以通过构造方法传入参数*/
public CarBuilder() {
}
public int getWheelNum() {
return wheelNum;
}
public CarBuilder setWheelNum(int wheelNum) {
this.wheelNum = wheelNum;
return this;
}
public int getDoorNum() {
return doorNum;
}
public CarBuilder setDoorNum(int doorNum) {
this.doorNum = doorNum;
return this;
}
public String getColor() {
return color;
}
public CarBuilder setColor(String color) {
this.color = color;
return this;
}
public ProductCar build() {
/*将Builder传给产品类*/
return new ProductCar(this);
}
}
}
public class Client {
public static void main(String args[]) {
ProductCar.CarBuilder builder = new ProductCar.CarBuilder();
ProductCar car = builder.setColor("红").setDoorNum(2).setWheelNum(4).build();
car.run();
}
}

概述

外观模式的主要目的在于让外部减少与子系统内部多个模块的交互,从而让外部能够更简单得使用子系统。它负责把客户端的请求转发给子系统内部的各个模块进行处理,Facade 的方法本身并不进行功能的处理,只是实现一个功能的组合调用。并且一般不会在外观类中定义一些子系统没有的功能,它主要负责组合已有功能来实现客户端的需求,而不是添加新的功能实现。

外观模式的优点

外观模式的好处有如下几点:

  • 由于Facade类封装了各个模块交互的过程,如果今后内部模块调用关系发生了变化,只需要修改Facade实现就可以了。
  • Facade实现是可以被多个客户端调用的,所以在Facade类中的方法是可以被共享的。
  • 即使有外观类的存在也可以不适用,而直接调用模块内的方法。这样就可以兼顾组合功能和细节功能。


如果没有外观类,客户端需要和子系统内部多个模块交互,客户端和这些模块之间都有依赖关系,任何一个模块的变动都可能会引起客户端的变动。使用外观类之后客户端就不需要去关心系统内部模块的变动情况了,客户端只需要和这个外部类有依赖关系,这样当系统内部多个模块发生变化的时候,这个变化可以被这个外观类吸收和消化,并不影响到客户端。
一般系统只需要一个外观类,所以可以使用单例或者私有化构造方法,并将其他方法声明为静态方法。

public class ModuleA {
public void testFuncA() {
System.out.println("This is Function From ModuleA");
}
}
public class ModuleB {
public void testFuncB() {
System.out.println("This is Function From ModuleB");
}
}
public class ModuleC {
public void testFuncC() {
System.out.println("This is Function From ModuleC");
}
}
public class Facade {
private ModuleA moduleA = null;
private ModuleB moduleB = null;
private ModuleC moduleC = null;
private static Facade mFacade = null;
private Facade(){
moduleA = new ModuleA();
moduleB = new ModuleB();
moduleC = new ModuleC();
}
public static Facade getInstance() {
if(mFacade == null) {
mFacade = new Facade();
}
return mFacade;
}

public void testOperation() {
moduleA.testFuncA();
moduleB.testFuncB();
moduleC.testFuncC();
}
}
public class Client {
public static void main(String arg[]) {
Facade.getInstance().testOperation();
}
}

概述

备忘录模式是为了在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后这个对象可以恢复到原先保存的状态。
备忘录模式引入一个存储状态的备忘录对象,它存储另一个对象在某个瞬时的内部状态。为了让外部无法访问这个对象的值一般把这个对象实现成为需要保存数据的对象的私有内部类。这样一来除了这个需要保存数据的对象,外部无法访问到这个备忘录对象的数据。

备忘录模式的组成

备忘录模式中有三个主要对象:

  • 备忘录对象:主要用来存储Originator对象的内部状态,另外它只能由Originator对象来访问它内部的数据,Originator 外部的对象不应该访问到备忘录对象内部的数据。
  • Originator对象:可以创建备忘录对象来保存某个时刻自身的状态,也可以使用备忘录来恢复内部状态。
  • 备忘录管理对象:负责保存备忘录对象,虽然管理者能够存取备忘录对象,但是它不能访问备忘录对象的内部数据。
    并不是一定要特别设定一个管理者对象,调用Originator 获得备忘录对象后,备忘录对象存放在哪里,哪个对象就可以算得上是管理者对象。管理者对象并不是只能管理一个备忘录对象,一个管理对象可以管理很多备忘录对象。并且还可以是多个不同类型的备忘录对象。

如果需要频繁创建备忘录对象,并且创建和应用备忘录对象来恢复状态的顺序是可控的,那么可以让备忘录进行增量存储,也就是备忘录仅仅存储Originator 内部相对于上一次存储状态后的增量改变。
如果在Originator 创建备忘录对象的时候,如果Originator对象中全部或者大部分的状态都需要保存,一个简单的方式就是直接克隆一个Originator对象,这时候备忘录对象中存放的就是一个Originator对象的实例。
从备忘录模式的功能和实现上,是可以把备忘录的数据实现成为离线存储的,也就是不仅仅限于存储在内存中,还可以把这些数据存储到文件中XML中数据库中。从而实现跨越会话的备份和恢复功能。
当然并不是所有的备份数据都需要离线存储,一般来讲需要存储很长时间,或者需要支持跨越会话的备份和恢复功能,或者希望系统关闭后还能被保存的备份数据的情况下使用离线备份。
离线备份的实现,只需要修改管理者对象,把保存备忘录对象的方法实现成为保存到文件中,而恢复对象实现成为读取文件就可以了,而对于其他的相关对象,主要是实现序列化,通过序列化来将对象存储到文件中。

public interface Memento {
}
public class Originator {

private String mState = null;

public Originator(String state) {
mState = state;
}

public void runSomeOperationBeforeBackup(String state) {
this.mState = state;
}
public void reportState() {
System.out.println(mState);
}
private static class MementoImp implements Memento {
private String backupState = null;
public MementoImp(String backupState) {
this.backupState = backupState;
}
public String getState() {
return this.backupState;
}
}
public Memento backUpState() {
return new MementoImp(this.mState);
}

public void restoreState(Memento memento) {
this.mState = ((MementoImp)memento).getState();
}
}
 public class MementoManger {

private Memento mMemento = null;

public void saveMemento(Memento memento) {
mMemento = memento;
}

public Memento getMemento() {
return this.mMemento;
}
}
public class Client {
public static void main(String[] args) {
Originator originator = new Originator("初始状态");
originator.runSomeOperationBeforeBackup("运行一段时间后的状态");
Memento memento = originator.backUpState();
MementoManger manager = new MementoManger();
manager.saveMemento(memento);
originator.runSomeOperationBeforeBackup("再次运行一段时间后的状态");
originator.reportState();
Memento memento1 = manager.getMemento();
originator.restoreState(memento1);
originator.reportState();
}
}

概述

在命令模式中有三个关键的对象:

  • 命令类:在标准的命令模式里面,命令实现类是没有真正实现命令要求的功能的,真正执行命令的功能是接收者。
  • 接收者:在命令模式中接收者可以是任意的类,它是持有真正执行方法的类,它可以处理多个命令,接收者提供的方法个数,名称功能和命令中的可以不一样,只要能够通过调用接收者的方法来实现命令对应的功能就可以了。
  • 命令触发器:命令出发器是持有命令的对象,但是请求究竟由谁处理,如何处理,发起请求的对象是不知道的,也就是发起请求的对象和真正实现的对象是解偶的,发起请求的对象只管发出命令,其他的就不管了。

命令模式的优点是实现了命令的发起对象和命令的具体实现对象—命令接收者的完全解耦,这样很方便扩展新的命令,只要实现新的命令对象,然后在装配的时候,把具体实现对象设置到命令中,就可以使用这个命令对象了,不用改变已有的实现。

public interface AbsCommand {
public void excuteCommand();
}
public class ConcreComand implements AbsCommand {
private CommandReceiver mReceiver = null;
public ConcreComand(CommandReceiver receiver) {
mReceiver = receiver;
}
public void excuteCommand() {
mReceiver.action();
}
}
public class CommandReceiver {
public void action() {
System.out.println("Receiver excute command");
}
}
public class CommandInvoker {
private AbsCommand mCommand = null;
public CommandInvoker(AbsCommand command) {
mCommand = command;
}
public void runCommand(){
mCommand.excuteCommand();
}
}
public class Client {
public static void main(String args[]) {
CommandReceiver receiver = new CommandReceiver();
AbsCommand command = new ConcreComand(receiver);
CommandInvoker invoker = new CommandInvoker(command);
invoker.runCommand();
}
}