共计 4082 个字符,预计需要花费 11 分钟才能阅读完成。
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 办法。
访问者模式合乎繁多职责准则,它的扩展性优良,又具备灵活性;然而它减少或者删除元素类不容易,违反了依赖倒置准则,依赖了具体类,没有依赖形象,毁坏了对象的封装性,具体元素对访问者公开细节。