乐趣区

关于java:23种设计模式Java版第七篇

ps:本文系转载文章,浏览原文可获取源码,文章开端有原文链接

ps:这一篇是写状态模式和访问者模式

1、状态模式

对于有状态的对象,容许不同的状态对象放入简单的“判断逻辑”,也容许状态对象的状态产生扭转时扭转它的行为。

状态模式具备以下几种角色:

(1)环境类角色:也称为上下文,外部领有一个以后状态的接口,负责具体状态的切换。

(2)形象状态角色:定义一个接口,给环境对象中的特定状态绝对应的行为进行调用,它有一个或多个办法。

(3)具体状态角色:实现形象状态所对应的形象办法,在符合条件的状况下进行状态切换。

“容许不同的状态对象放入简单的“判断逻辑””这句话就给读者本人去论证了,上面咱们论证一下“容许状态对象的状态产生扭转时扭转它的行为”这句话,用代码举个例子:

(1)形象状态角色,新建一个 State 接口:

public interface State {

public void handle();

}

(2)具体状态角色,新建一个 CheckedInState 类并实现 State 接口:

public class CheckedInState implements State{

@Override
public void handle() {System.out.println("房间曾经入住");
}

}

(3)具体状态角色,新建一个 BookedState 类并实现 State 接口:

public class BookedState implements State{

@Override
public void handle() {System.out.println("房间曾经预约");
}

}

(4)具体状态角色,新建一个 FreeState 类并实现 State 接口:

public class FreeState implements State{

@Override
public void handle() {System.out.println("房间闲暇,没人住");
}

}

(5)环境类角色,新建一个 HomeContext 类:

public class HomeContext {

private State state;
public void setState(State state) {
  this.state = state;
  state.handle();}
public State getState() {return state;}

}

(6)客户端进行测试调用:

    HomeContext home = new HomeContext();
    home.setState(new CheckedInState());
    home.setState(new BookedState());
    home.setState(new FreeState());
    State state = home.getState();
    state.handle();

日志打印如下所示:

图片

从日志里能够看出环境类角色 HomeContext 每设置一次不同的状态,它不同状态(CheckedInState、BookedState、FreeState)的行为就会跟着去扭转。

状态模式是将状态放到一个环境类中,只须要扭转对象状态即可扭转对象的行为,多个环境对象能够共享一个状态对象,从而缩小零碎中对象的个数,同时状态类职责明确,有利于程序的扩大;应用状态模式时,客户端要扭转状态,然而状态的扭转可能是不简略的;每个状态都要写一个子类,这样会减少类文件的数量。

2、访问者模式

把某一种数据结构中元素的操作分离出来封装成一个类,在不扭转数据结构的前提下元素新的操作访问者扭转而扭转。

访问者模式具备以下几种角色:

(1)形象访问者角色:申明一个拜访具体元素的接口,形象办法中的参数类型标识了被拜访的具体元素。

(2)具体访问者角色:实现形象访问者角色中申明的所有形象办法,明确访问者拜访元素的具体操作。

(3)形象元素角色:申明一个具体元素做某些性能的接口。

(4)具体元素角色:实现形象元素角色提供的形象办法,同时具体元素也能够有自身业务逻辑的行为。

(5)对象构造角色:一个蕴含元素角色的容器个别是 List 等聚合类。

上面用代码举个例子:

(1)形象访问者角色,新建一个 IVisitor 接口:

public interface IVisitor {

public void visit(Element1 element);
public void visit(Element2 element);

}

(2)具体访问者角色,新建一个 Concrete1 类并实现 IVisitor 接口:

public class Concrete1 implements IVisitor{

private static final String TAG = "Concrete1 类的 visit 办法 -->";
@Override
public void visit(Element1 element) {String msg = TAG + element.operation();
    System.out.println(msg);
}

@Override
public void visit(Element2 element) {String msg = TAG + element.operation();
    System.out.println(msg);
}

}

(3)具体访问者角色,新建一个 Concrete2 类并实现 IVisitor 接口:

public class Concrete2 implements IVisitor{

private static final String TAG = "Concrete2 类的 visit 办法 -->";
@Override
public void visit(Element1 element) {String msg = TAG + element.operation();
    System.out.println(msg);
}

@Override
public void visit(Element2 element) {String msg = TAG + element.operation();
    System.out.println(msg);
}

}

(4)形象元素角色,新建一个 IElement 接口:

public interface IElement {
public void accept(IVisitor visitor);
}
(5)具体元素角色,新建一个 Element1 类并实现 IElement 接口:

public class Element1 implements IElement{

@Override
public void accept(IVisitor visitor) {visitor.visit(this);
}

public String operation() {return "调用 Element1 类的 operation 办法";}

}

(6)具体元素角色,新建一个 Element2 类并实现 IElement 接口:

public class Element2 implements IElement{

@Override
public void accept(IVisitor visitor) {visitor.visit(this);
}

public String operation() {return "调用 Element2 类的 operation 办法";}

}

(7)对象构造角色,新建一个 Structure 类:

public class Structure {

private List<IElement> list = new ArrayList<IElement>();

public void accept(IVisitor visitor) {
    IElement element = null;
    for (int i = 0; i < list.size();i++) {element = list.get(i);
       element.accept(visitor);
    }
}

public void add(IElement element) {list.add(element);
}

public void remove(IElement element) {list.remove(element);
}

}

(8)客户端进行测试调用:

    Structure s = new Structure();
    s.add(new Element1());
    s.add(new Element2());
    System.out.println("调用具体访问者 Concrete1------------------------");
    IVisitor visitor = new Concrete1();
    s.accept(visitor);
    System.out.println("调用具体访问者 Concrete2------------------------");
    visitor = new Concrete2();
    s.accept(visitor);

日志打印如下所示:

图片

咱们把具体的元素 Element1 和 Element2 存储到对象构造类 Structure 中的容器 List,而后实例化具体访问者 Concrete1 和 Concrete2 并将它们参数丢到 Structure 类中的 accept 办法中;我就拿 Concrete1 作为参数解释一下,Concrete2 也是一样的思路;在 Structure 类中的 accept 办法中先遍历 List 里的元素,而后调用元素 IElement(实现者 Element1、Element2)的 accept 办法并把 IVisitor(实现者 Concrete1)作为参数传过来,Element1 和 Element2 的 accept 办法又调用 Concrete1 的 visit 办法,Concrete1 的 visit 办法又调用 Element1 和 Element2 的 operation 办法,思路就是具体元素 Element1 和 Element2 通过访问者 Concrete1 间接的调用本人的 operation 办法。

访问者模式合乎繁多职责准则,它的扩展性优良,又具备灵活性;然而它减少或者删除元素类不容易,违反了依赖倒置准则,依赖了具体类,没有依赖形象,毁坏了对象的封装性,具体元素对访问者公开细节。

退出移动版