23种设计模式Java版第七篇
Posted 小二玩编程
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 方法。
访问者模式符合单一职责原则,它的扩展性优秀,又具有灵活性;但是它增加或者删除元素类不容易,违反了依赖倒置原则,依赖了具体类,没有依赖抽象,破坏了对象的封装性,具体元素对访问者公开细节。
以上是关于23种设计模式Java版第七篇的主要内容,如果未能解决你的问题,请参考以下文章