状态模式和策略模式很类似,简直就是亲兄弟一样。而访问者模式其实和观察者模式也很类似。所以我们的设计模式设计到最后,可能就会存在一种模式里有另一种模式的影子。所以我们要搞清楚它们之间的区别。
1、状态模式
简要说明
允许一个对象在其内部改变时改变它的行为
速记关键字
状态变成类
类图如下
状态模式主要用来解决对象在多种状态转换时,需要对外输出不同的行为的问题。比如订单从待付款到待收货的咋黄台发生变化,执行的逻辑是不一样的。
所以我们将状态抽象为一个接口或者抽象类,对不同状态进行封装成单独的实体,用于实现各种状态处理的逻辑。
再设计一个上下文类,它组合了状态接口,用于发送请求。针对不同的状态提供不同的处理方法即可。
Java代码实现
/**
* 状态接口 提供处理状态的方法
*/
public interface IState {
// 处理状态,交给实现类实现
void handleState();
}
/**
* 未付款状态
*/
public class UnpaidState implements IState{
@Override
public void handleState() {
System.out.println("下单成功,订单状态为待付款");
}
}
/**
* 已付款状态
*/
public class PaidState implements IState{
@Override
public void handleState() {
System.out.println("支付成功,订单状态为已付款");
}
}
/**
* 已取消状态
*/
public class CancelState implements IState{
@Override
public void handleState() {
System.out.println("订单取消支付,订单状态为已取消");
}
}
/**
* 订单状态上下文类
*/
public class Context {
// 组合订单状态
private final IState state;
public Context(IState state) {
this.state = state;
}
// 提供处理订单方法
public void handleOrderByState(){
state.handleState();
}
}
/**
* 测试类
*/
public class Client {
public static void main(String[] args) {
// 创建上下文并创建未支付状态
Context context = new Context(new UnpaidState());
context.handleOrderByState();
// 创建上下文并创建已支付状态
Context context2 = new Context(new PaidState());
context2.handleOrderByState();
}
}
结果输出
其实我们可以看出来,状态模式和策略模式非常像,都有一个Context类,都有一个接口或抽象类被Context组合。而后抽象类或接口有自己的不同实现。
它们确实很像,但是它们确实有区别,因为状态模式围绕着状态的变化,它的子类之间的状态是可以进行转换的,比如订单状态由未付款变为已付款。但是策略模式则不会,只会二者取其一,进行一种策略操作。
2、访问者模式
简要说明
表示一个作用域某对象结构中的个元素的操作,使得在不改变各元素的前提下定义作用域这些元素的新操作。
速记关键字
数据与操作分离
类图如下
角色说明
- Visitor(抽象访问者):为每种具体的被访问者(ConcreteElement)声明一个访问操作
- ConcreteVisitor(具体访问者):实现对被访问者(ConcreteElement)的具体访问操作,所以需要组合多个元素,也就是组合一组元素集合
- Element(抽象被访问者):通常有一个Accept方法,用来接收/引用一个抽象访问者对象(基本原理)
- ConcreteElement(具体被访问者对象):实现Accept抽象方法,通过传入的具体访问者参数、调用具体访问者对该对象的访问操作方法实现访问逻辑
- Clent、ObjectStructure(客户端访问过程测试环境):该过程中,被访问者通常为一个集合对象,通过对集合的遍历完成访问者对每一个被访问元素的访问操作;
Java代码实现
/**
* 定义被访问接口
*/
public interface Person {
// 提供一个方法,让访问者可以访问
void accept(Action action);
}
/**
* 访问者,这里提供了多个访问方法,从而获取多个不同的访问结果,它们的参数分别对应具体的被访问元素
*/
public interface Action {
// 得到男性 的测评
void getManResult(Man man);
// 得到女的 测评
void getWomanResult(Woman woman);
}
/**
* 被访问者元素男人实现,传入自己给访问者访问
*/
public class Man implements Person{
@Override
public void accept(Action action) {
action.getManResult(this);
}
}
/**
* 被访问者元素女人实现,传入自己给访问者访问
*/
public class Woman implements Person{
@Override
public void accept(Action action) {
action.getWomanResult(this);
}
}
/**
* 访问者实现类 对不同的被访问元素做不同的访问
*/
class Success implements Action {
@Override
public void getManResult(Man man) {
System.out.println("男人给的评价: 歌手很表演很nice");
}
@Override
public void getWomanResult(Woman woman) {
System.out.println("女人给的评价: 歌手很表演很nice");
}
}
class Normal implements Action {
@Override
public void getManResult(Man man) {
System.out.println("男人给的评价是: 歌手很表演比较普通");
}
@Override
public void getWomanResult(Woman woman) {
System.out.println("女人给的评价是: 歌手很表演比较普通");
}
}
public class Fail implements Action {
@Override
public void getManResult(Man man) {
System.out.println("男人给的评价: 歌手很表演有点糟糕");
}
@Override
public void getWomanResult(Woman woman) {
System.out.println("女人给的评价: 歌手很表演有点糟糕");
}
}
/**
* 数据结构,管理很多人(Man , Woman)
*/
class ObjectStructure {
//维护了一个集合
private List<Person> persons = new LinkedList<>();
//添加
public void add(Person p) {
persons.add(p);
}
//删除
public void delete(Person p) {
persons.remove(p);
}
// 显示测评情况(便利)
public void show(Action action) {
for (Person p : persons) {
p.accept(action);
}
}
}
/**
* 测试类
*/
public class Client {
public static void main(String[] args) {
// 使用数据结构来创建
ObjectStructure os = new ObjectStructure();
// 添加我们我们的访问者
os.add(new Man());
os.add(new Woman());
// 创建成功的被访问者
Success success = new Success();
// 通过数据结果遍历访问者,然后进行访问成功的数据
os.show(success);
System.out.println("========================");
// 创建失败的被访问者
Fail fail = new Fail();
// 通过数据结果遍历访问者,然后进行访问失败的数据
os.show(fail);
System.out.println("========================");
// 创建中肯的的被访问者
Normal normal = new Normal();
os.show(normal);
}
}
其实访问者模式和观察者模式的思想也非常类似,代码实现也很类似。都会提供一个管理被访问者/观察者集合,提供新增和删除方法,并且提供一个遍历集合的方法,并通知所有元素或者指定元素的方法。
它们只是应用场景不一样,其实类图都很类似。
结果输出
3、小结
其实我们可以看出,状态模式和策略模式很类似,简直就是亲兄弟一样。而访问者模式其实和观察者模式也很类似。所以我们的设计模式设计到最后,可能就会存在一种模式里有另一种模式的影子。所以我们要搞清楚它们之间的区别。