设计模式09-行为型模式2(状态模式/策略模式/Java)

5.4 状态模式

5.4.1 状态模式的定义

1.模式动机:有些对象具有多种状态,这些状态在某些情况下能够相互转换,对象在不同的状态下将具有不同的行为,将拥有状态的对象中和状态的行为分离。

2.模式定义:允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类

5.4.2 状态模式的结构与分析
  • 环境类是指拥有状态的对象,可以对状态进行切换。
  • 抽象状态类是具体状态类的父类,各状态的行为封装在具体的状态类中,对于客户端而言,无须关心对象状态的转换以及对象所处的当前状态,无论对于何种状态的对象,客户端都可以一致处理。
java 复制代码
public abstract class State {
    public abstract void handle();
}

public class ConcreteState extends State{
    @Override
    public void handle() {

    }
}

public class Context {
    private State state;
    public void setState(State state) {
        this.state = state;
    }
    public void request() {
        state.handle();
    }
}
5.4.3 状态模式的案例

在某论坛系统中,用户可以发表留言,发表留言将增加积分;用户也可以回复留言,回复留言也将增加积分;用户还可以下载文件,下载文件将扣除积分。该系统用户分为三个等级,分别是新手、高手和专家,这三个等级对应三种不同的状态,这三种状态分别定义如下:

(1) 如果积分小于100分,则为新手状态,用户可以发表留言、回复留言,但是不能下载文件。如果积分大于等于1000分,则转换为专家状态;如果积分大于等于100分,则转换为高手状态。

(2) 如果积分大于等于100分但小于1000分,则为高手状态,用户可以发表留言、回复留言,还可以下载文件,而且用户在发表留言时可以获取双倍积分。积分小于100分,转换为新手状态;如果积分大于等于1000分,则转换为专家状态;如果下载文件后积分小于0,则不能下载该文件。

(3) 如果积分大于等于1000分,则为专家状态,用户可以发表留言、回复留言和下载文件,用户除了在发表留言时可以获取双倍积分外,下载文件只扣除所需积分的一半。积分小于100分,则转换为新手状态;积分小于1000分,但大于等于100,则转换为高手状态;如果下载文件后积分小于0,则不能下载该文件。

由于上述类图将point放到了状态方面,不好理解,下面代码将point放到ForumAccount中

java 复制代码
public class ForumAccount {
    private String username;
    private State state;
    private int point;

    public ForumAccount(String username) {
        this.username = username;
        this.point = 0;
        this.state = new PrimaryState(this);
    }

    public void writeNote(int point) {
        state.writeNote(point);
    }
    public void replyNote(int point) {
        state.replyNote(point);
    }
    public void downloadNote(int point) {
        state.downloadNote(point);
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public State getState() {
        System.out.println(state.getStateName());
        return state;
    }

    public void setState(State state) {
        this.state = state;
    }

    public int getPoint() {
        return point;
    }

    public void setPoint(int point) {
        this.point = point;
    }

}
java 复制代码
public abstract class State {
    protected ForumAccount forumAccount;
    protected String stateName;
    public State(ForumAccount forumAccount) {
        this.forumAccount = forumAccount;
    }
    public abstract void writeNote(int point);
    public abstract void replyNote(int point);
    public abstract void downloadNote(int point);
    public void updateState(int point) {
        if (point >= 1000) {
            forumAccount.setState(new HighState(forumAccount));
        } else if (point >= 100) {
            forumAccount.setState(new MiddleState(forumAccount));
        } else {
            forumAccount.setState(new PrimaryState(forumAccount));
        }
    }
    public String getStateName() {
        return stateName;
    }
}
java 复制代码
public class PrimaryState extends State{
    public PrimaryState(ForumAccount forumAccount) {
        super(forumAccount);
        this.stateName = "新手级别";
    }

    @Override
    public void writeNote(int point) {
        System.out.println("新手版-写评论");
        forumAccount.setPoint(forumAccount.getPoint() + point);
        updateState(forumAccount.getPoint());
    }

    @Override
    public void replyNote(int point) {
        System.out.println("新手版-回复评论");
        forumAccount.setPoint(forumAccount.getPoint() + point);
        updateState(forumAccount.getPoint());
    }

    @Override
    public void downloadNote(int point) {
        System.out.println("新手状态-无法下载文件");
    }
}
java 复制代码
public class MiddleState extends State{
    public MiddleState(ForumAccount forumAccount) {
        super(forumAccount);
        this.stateName = "高手级别";
    }

    @Override
    public void writeNote(int point) {
        System.out.println("高手版-写评论");
        forumAccount.setPoint(forumAccount.getPoint() + point);
        updateState(forumAccount.getPoint());
    }

    @Override
    public void replyNote(int point) {
        System.out.println("高手版-回复评论");
        forumAccount.setPoint(forumAccount.getPoint() + point * 2);
        updateState(forumAccount.getPoint());
    }

    @Override
    public void downloadNote(int point) {
        if (point > forumAccount.getPoint()) {
            System.out.println("积分不足,不能下载");
        } else {
            System.out.println("高手版-下载文件");
            forumAccount.setPoint(forumAccount.getPoint() - point);
            updateState(forumAccount.getPoint());
        }
    }
}
java 复制代码
public class HighState extends State {
    public HighState(ForumAccount forumAccount) {
        super(forumAccount);
        this.stateName = "专家级别";
    }

    @Override
    public void writeNote(int point) {
        System.out.println("专家版-写评论");
        forumAccount.setPoint(forumAccount.getPoint() + point);
        updateState(forumAccount.getPoint());
    }

    @Override
    public void replyNote(int point) {
        System.out.println("专家版-回复评论");
        forumAccount.setPoint(forumAccount.getPoint() + point * 2);
        updateState(forumAccount.getPoint());
    }

    @Override
    public void downloadNote(int point) {
        if (point / 2 > forumAccount.getPoint()) {
            System.out.println("积分不足,不能下载");
        } else {
            System.out.println("专家版-下载文件");
            forumAccount.setPoint(forumAccount.getPoint() - point / 2);
            updateState(forumAccount.getPoint());
        }
    }
}
5.4.4 状态模式的优缺点
优点 缺点
1.封装了状态的转换规则,可以对状态转换代码进行集中管理,而不是需要冗长的if-else判断 1.会增加系统中类和对象的个数,导致系统运行开销增大
2.将所有与某个状态有关的行为放到一个类中,注入一个不同的状态对象即可使环境对象拥有不同行为 2.结构与实现都较为复杂,如果使用不当将导致程序结构和代码混乱,增加系统设计的难度
3.允许状态转换逻辑与状态对象合成一体,而不是提供一个巨大的条件语句块 3.对开闭原则的支持并不太好
4.可让多个环境对象共享一个状态对象,从而减少系统中对象的个数
5.4.5 状态模式的适用场景
  • 对象的行为依赖于它的状态(例如某些属性值),状态的改变将导致行为的变化

  • 在代码中包含大量与对象状态有关的条件语句,这些条件语句的出现会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,并且导致客户类与类库之间的耦合增强

5.5 策略模式

5.5.1 策略模式的定义

1.模式动机:解决某一问题的一个算法族,允许用户从该算法族中任选一个算法解决某一问题,同时可以方便地更换算法或者增加新的算法。

2.模式定义:定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。

5.5.2 策略模式的结构与分析
  • 它将每一个算法封装在一个称为具体策略的类中,同时为其提供统一的抽象策略类,而使用这些算法完成某一业务功能的类称为环境类。

  • 策略模式实现了算法定义和算法使用的分离,它通过继承和多态的机制实现对算法族的使用和管理,是一种简单易用的对象行为型模式。

  • 各算法是由客户端决定的,不是策略模式自己决定的。

java 复制代码
public abstract class Strategy {
    public abstract void algorithm();
}
public class ConcreteStrategy extends Strategy{
    @Override
    public void algorithm() {
    }
}
public class Context {
    private Strategy strategy;

    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    public void request() {
        strategy.algorithm();
    }
}
5.5.3 策略模式的案例
java 复制代码
public class Person {
    private String name;
    private TravelStrategy travelStrategy;
    public Person(String name) {
        this.name = name;
    }

    public void setTravelStrategy(TravelStrategy travelStrategy) {
        this.travelStrategy = travelStrategy;
    }

    public void travel() {
        System.out.print(this.name);
        travelStrategy.travel();
    }
}

public interface TravelStrategy {
    public void travel();
}

public class TrainStrategy implements TravelStrategy{
    @Override
    public void travel() {
        System.out.println("乘坐火车去旅行");
    }
}

public class Main {
    public static void main(String[] args) {
        TravelStrategy bean = (AirPlaneTravelStrategy) XMLUtil.getBean();
        Person person = new Person("xyx");
        person.setTravelStrategy(bean);
        person.travel();
    }
}
5.5.4 策略模式的优缺点
优点 缺点
1.符合开闭原则,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为 1.客户端必须知道所有的策略类,并自行决定使用哪一个策略类
2.提供了管理相关的算法族的办法,避免多重条件选择语句 2.将造成系统产生很多具体策略类
3.提供了一种可以替换继承关系的办法 3.无法同时在客户端使用多个策略类
5.5.5 策略模式的适用场景
  • 一个系统需要动态地在几种算法中选择一种

  • 避免使用难以维护的多重条件选择语句

  • 不希望客户端知道复杂的、与算法相关的数据结构,提高算法的保密性与安全性

5.5.6 状态模式和策略模式的对比
状态模式 策略模式
环境类状态个数 多个状态,可以相互转化 存在一个状态,一旦选择不能随意改变
环境类与状态类关系 若环境类会影响状态的改变,为双向关联关系 单向的关联关系
客户端 无需知道具体状态,会根据行为自动切换 需要知道所选策略
行为 各状态下有多个行为 一个行为的多种实现方式
相关推荐
大耳朵土土垚8 分钟前
【Linux】日志设计模式与实现
linux·运维·设计模式
小王子10243 小时前
设计模式Python版 组合模式
python·设计模式·组合模式
linwq85 小时前
设计模式学习(二)
java·学习·设计模式
.生产的驴1 天前
MYSQL 商城系统设计 商品数据表的设计 商品 商品类别 商品选项卡 多表查询
数据库·mysql·搜索引擎·性能优化·云计算·状态模式·多分类
你又食言了哦1 天前
C++实现状态模式
开发语言·c++·状态模式
小王子10241 天前
设计模式Python版 桥接模式
python·设计模式·桥接模式
Cikiss2 天前
「全网最细 + 实战源码案例」设计模式——桥接模式
java·后端·设计模式·桥接模式
纪元A梦2 天前
Java设计模式:行为型模式→观察者模式
java·观察者模式·设计模式
荣--2 天前
DAB实现中用到的主要设计模式
设计模式·dab
CaraYQ2 天前
【vue项目权限控制方案】
前端·vue.js·状态模式