Шаблоны проектирования. Лекция 8. Шаблоны состояний

Java

Введение

Паттерн состояния в основном решает ситуацию, когда условное выражение, управляющее переходом состояния объекта, слишком сложное. Сложная логика суждения может быть упрощена путем переноса логики суждения о состоянии на ряд классов, представляющих разные состояния.

В сложном бизнесе может быть большое количество логических суждений, таких как if else, которые очень опасны и сложны для дальнейшего обслуживания. Шаблон состояния также локализует поведение, связанное с конкретным состоянием, и разделяет поведение различных состояний.

Можно исключить большое количество операторов условного перехода, а взаимозависимость между ними можно уменьшить за счет внутренней передачи состояния.

  • Мышление: в чем разница между шаблоном стратегии, шаблоном цепочки ответственности и шаблоном состояния

настройки сцены

Например, если вы участвуете в разработке сетевого диска Baidu, возможны следующие распространенные сценарии:

уровень членства разрешение
обычный пользователь Хранить фотографии, документы
член Чрезвычайно быстрая загрузка, 5T пространство...
супер член Автоматическое резервное копирование небольших видеороликов, воспроизведение аудио и видео с удвоенной скоростью...

Простая реализация

Класс получения разрешений

package design.pattern;

import java.util.ArrayList;

public class UserRule {

    /**
     * 等级 1普通用户 2会员 3超级会员
     */
    private Integer level = 1;

    /**
     * 权限容器
     */
    private ArrayList<String> ruleList = new ArrayList<String>() {
        {
            add("上传文件");
            add("下载文件");

        }
    };

    public UserRule(Integer level) {
        this.level = level;
    }

    /**
     * 获取权限列表
     *
     * @return
     */
    public ArrayList<String> getRuleList() {

        if (this.level == 2) {  //会员
            //todo 权限获取
            ruleList.add("极速下载");
            ruleList.add("5T空间");
        } else if (this.level == 3) { //超级会员
            //todo 权限获取
            ruleList.add("光速下载");
            ruleList.add("10T空间");
            ruleList.add("小视频自动备份");
            ruleList.add("音视频倍速播放");
        }

        return ruleList;
    }
}

Звонок клиента:

Integer requestLevel = 3;

UserRule userRule = new UserRule(requestLevel);

ArrayList<String> ruleList = userRule.getRuleList();

//打印权限
System.out.println("会员等级" + requestLevel + "权限列表:");
for (Object object : ruleList) {
    System.out.println(object);
}

вывод:

会员等级3权限列表:
上传文件
下载文件
光速下载
10T空间
小视频自动备份
音视频倍速播放

думать:

Кажется, что наш код достаточно прост, чтобы удовлетворить потребность в возврате разрешений на основе уровня

Мы фокусируемся на бизнес-логике получения списка разрешений в соответствии с различными условиями и обработки различных задач.Если мы добавим больше уровней, более сложные методы расчета разрешений и другие функции, это если еще будет еще больше.


После того, как я только что закончил говорить, он может стать огромным, и продукт пришел ко мне и попросил у меня версию 2.0.

  • Продукт: в последнее время отзывы рынка говорят о том, что наши участники не очень хорошо продаются, теперь нам нужно добавить небольшую функцию.
  • я: ...
  • Продукт: При возвращении на текущий уровень верните ему информацию о разрешении, которая будет получена на следующем уровне, пусть он ее увидит, и поощряйте пользователей выполнять задания или платить.
  • Я: Разве у нас нет списка для прямого сравнения, зачем ему отдельно напоминать?
  • Продукт: Вы продукт или я продукт?
  • Я: Я повторяю «Каждый является менеджером по продукту».

Используйте сообщение режима состояния, чтобы избавиться от этих избыточных if else (и, конечно же, последнее требование)

Мы обнаружили, что если мы добавим разрешение на возврат к следующей версии, этого действительно достаточно. Через несколько дней может не быть спроса, и этот метод кажется сломанным. Похоже, его нужно оптимизировать.

Сначала мы создаем абстрактный класс (функция ядра удобна для ограничений и передачи подкласса)

State.java

package design.pattern.Rules;

import design.pattern.UserRule;
import design.pattern.UserVo;

import java.util.ArrayList;

public abstract class State {

    /**
     * 用户对象
     */
    protected UserRule userRule;

    /**
     * 权限容器
     */
    protected ArrayList<String> ruleList = new ArrayList<String>() {
        {
            add("上传文件");
            add("下载文件");

        }
    };

    public State(UserRule userRule) {
        this.userRule = userRule;
    }

    public abstract ArrayList<String> getRuleList(UserVo userVo);

}

На первом этапе нам нужен простой объект параметра (здесь мы используем объект представления)

UserVo.java

package design.pattern;

public class UserVo {

    private String name;

    private Integer level;

    public UserVo(String name, Integer level) {
        this.name = name;
        this.level = level;
    }

    public String getName() {
        return name;
    }

    public Integer getLevel() {
        return level;
    }
}

Наследуйте класс состояния State.java и реализуйте соответствующий класс возврата члена.

package design.pattern.Rules;

import design.pattern.UserRule;
import design.pattern.UserVo;

import java.util.ArrayList;

/**
 * 一类会员
 */
public class MemberOne extends State {

    public MemberOne(UserRule userRule) {
        super(userRule);
    }

    /**
     * 获取权限列表
     *
     * @return
     */
    public ArrayList<String> getRuleList(UserVo userVo) {

        //如果是一类会员(普通)
        if (userVo.getLevel() == 1) {
            return ruleList;
        } else {
            userRule.setState(new MemberTwo(userRule)); //设置下一级别类
            return userRule.getRuleList(userVo);  //获取下一个级别的详情
        }
    }
}

UserRule.java (класс моста)

package design.pattern;

import design.pattern.Rules.MemberOne;
import design.pattern.Rules.State;

import java.util.ArrayList;

public class UserRule {

    /**
     * 具体权限对象
     */
    private State currentRule;

    public UserRule() {
        currentRule = new MemberOne(this);
    }

    /**
     * 设置权限对象
     *
     * @param state
     */
    public void setState(State state) {
        this.currentRule = state;
    }


    public ArrayList<String> getRuleList(UserVo userVo) {
        return this.currentRule.getRuleList(userVo);
    }

}

Класс userRule – это класс, полный условных суждений перед оптимизацией, который отделяет ее. Его можно понимать как класс-мост, который вызывает классы внутри и предоставляет доступ к классам извне.

Объект userVo — это наш объект параметра, который в основном используется для оценки уровня.Если он не выполняется, сбрасывается следующий класс правил обработки, а также вызывается метод списка правил.

Оставшиеся два класса членства

package design.pattern.Rules;

import design.pattern.UserRule;
import design.pattern.UserVo;

import java.util.ArrayList;

/**
 * 三类会员
 */
public class MemberTwo extends State {

    public MemberTwo(UserRule userRule) {
        super(userRule);
    }

    /**
     * 获取权限列表
     *
     * @return
     */
    public ArrayList<String> getRuleList(UserVo userVo) {

        if (userVo.getLevel() == 2) {
            ruleList.add("极速下载");
            ruleList.add("5T空间");
            return ruleList;
        }else{
            userRule.setState(new MemberThree(userRule));
            return userRule.getRuleList(userVo);
        }
    }
}

package design.pattern.Rules;

import design.pattern.UserRule;
import design.pattern.UserVo;

import java.util.ArrayList;

/**
 * 三类会员
 */
public class MemberThree extends State {

    public MemberThree(UserRule userRule) {
        super(userRule);
    }

    /**
     * 获取权限列表
     *
     * @return
     */
    public ArrayList<String> getRuleList(UserVo userVo) {

        //最高级
        ruleList.add("光速下载");
        ruleList.add("10T空间");
        ruleList.add("小视频自动备份");
        ruleList.add("音视频倍速播放");
        return ruleList;
    }
}

Чтобы облегчить передачу и управление параметрами, мы используем отдельный класс объекта представления.

UserVo.java

package design.pattern;

public class UserVo {

    private String name;

    private Integer level;

    public UserVo(String name, Integer level) {
        this.name = name;
        this.level = level;
    }

    public String getName() {
        return name;
    }

    public Integer getLevel() {
        return level;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setLevel(int level) {
        this.level = level;
    }
}

Звонок клиента:

UserVo userVo = new UserVo("小红", 1);

UserRule userRule = new UserRule();
ArrayList<String> ruleList = userRule.getRuleList(userVo);

//打印
System.out.println("用户" + userVo.getName() + "当前权限如下:");
for (Object object : ruleList) {
    System.out.println(object);
}

//他的下个权限可以获得
userVo.setLevel(userVo.getLevel() + 1);
ruleList = userRule.getRuleList(userVo);
System.out.println("用户" + userVo.getName() + "将要权限如下:");
for (Object object : ruleList) {
    System.out.println(object);
}

output:

用户小红当前权限如下:
上传文件
下载文件
用户小红将要权限如下:
上传文件
下载文件
极速下载
5T空间

Основной код:

if (userVo.getLevel() == 1) {
    return ruleList;
} else {
    userRule.setState(new MemberTwo(userRule)); //设置下一级别类
    return userRule.getRuleList(userVo);  //获取下一个级别的详情
}

Подумайте о проблемах с этим кодом, как его оптимизировать?

UML-диаграмма шаблона состояния аналогична шаблону стратегии.

В чем разница между шаблоном стратегии и шаблоном состояния?

Шаблон стратегии очень похож на шаблон состояния, но между ними есть существенные различия.

  • Шаблон стратегии предоставляет определенные классы стратегий, и вызывающая сторона должна понимать различия каждой стратегии, чтобы правильно ее использовать.
  • Смена состояния состояния модуса изменяется его внутренними условиями и не имеет ничего общего с внешним миром, и у этих двух есть существенные различия в мышлении.
userRule.setState(new MemberTwo(userRule));),

Режим контрастной стратегии:Подробное объяснение режима стратегии

Для получения более захватывающего контента, пожалуйста, обратите внимание на восторженный публичный аккаунт Xiaoyu.