概述
一、概述
我们工作的业务代码从注释、命名、方法和异常等多方面实现整洁代码,但是感觉不够简洁,不够优雅,因为这是设计上的不足,总结就是抽象不够、可读性低、不够健壮。那这些就用到了设计模式。
java本身没有设计模式,但是随着时代的发展,写代码是人多了,他们便总结出了一套能提高开发和维护效率的套路,这就是设计模式。设计模式不是什么教条或者范式,它可以说是一种在特定场景下普适且可复用的解决方案,是一种可以用于提高代码可读性、可扩展性、可维护性的最佳实践。
二、任务模型设计
我目前在职的公司主营业务是智能语音外呼,主要是用机器人语音外呼替代人工,客户上传的数据以一个任务的维度存储,这就涉及外呼任务状态的流转变更,以及状态变更后的消息通知。
// 外呼任务状态枚举
@AllArgsConstructor
@Getter
enum TaskState {
INIT("未开始"),
ONGOING( "进行中"),
PAUSED("暂停中"),
FINISHED("已完成"),
EXPIRED("已过期") ;
private final String message;
}
// 外呼行为枚举
@AllArgsConstructor
@Getter
enum ActionType {
START(1, "开始"),
STOP(2, "暂停"),
ACHIEVE(3, "完成"),
EXPIRE(4, "过期") ;
private final int code;
private final String message;
}
状态变更功能代码:
class Task {
private Long taskId;
// 任务的默认状态为未开始
private TaskState state = TaskState.INIT;
// 活动服务
private ActivityService activityService;
// 任务管理器
private TaskManager taskManager;
// 使用条件分支进行任务更新
public void updateState(ActionType actionType) {
if (state == TaskState.INIT) {
if (actionType == ActionType.START) {
state = TaskState.ONGOING;
}
} else if (state == TaskState.ONGOING) {
if (actionType == ActionType.ACHIEVE) {
state = TaskState.FINISHED;
// 任务完成后进对外部服务进行通知
activityService.notifyFinished(taskId);
taskManager.release(taskId);
} else if (actionType == ActionType.STOP) {
state = TaskState.PAUSED;
} else if (actionType == ActionType.EXPIRE) {
state = TaskState.EXPIRED;
}
} else if (state == TaskState.PAUSED) {
if (actionType == ActionType.START) {
state = TaskState.ONGOING;
} else if (actionType == ActionType.EXPIRE) {
state = TaskState.EXPIRED;
}
}
}
}
在上述的实现中,updateState方法中完成了2个重要的功能:
- 接收不同的行为,然后更新当前任务的状态;
- 当任务完成时,通知任务所属的活动和任务管理器。
缺点:
- 如果分支变多,这里的代码就会变得臃肿,难以维护,可读性低。
- 如果增加新的状态时要添加新的if-else语句,那只能在原有代码上修改。
就是以上代码,违背了面向对象编程的开闭原则、单一原则以及迪米特法则。 参考我上篇写的设计模式-短信发送策略
这里同样可以通过设计模式去优化。首先是状态流转的控制可以使用状态模式,其次,任务完成时的通知可以用到观察者模式。
状态模式:对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。状态模式包含以下主要角色:
- 环境类(Context)角色:也称为上下文,它定义了客户端需要的接口,内部维护一个当前状态,并负责具体状态的切换。
- 抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为,可以有一个或多个行为。
- 具体状态(Concrete State)角色:实现抽象状态所对应的行为,并且在需要的情况下进行状态切换。
// 任务状态抽象接口
interface State {
// 默认实现,不做任何处理
default void update(Task task, ActionType actionType) {
// do nothing
}
}
// 具体状态任务初始状态
class TaskInit implements State {
@Override
public void update(Task task, ActionType actionType) {
if (actionType == ActionType.START) {
task.setState(new TaskOngoing());
}
}
}
// 具体状态任务进行状态
class TaskOngoing implements State {
private ActivityService activityService;
private TaskManager taskManager;
@Override
public void update(Task task, ActionType actionType) {
if (actionType == ActionType.ACHIEVE) {
task.setState(new TaskFinished());
// 通知
activityService.notifyFinished(taskId);
taskManager.release(taskId);
} else if (actionType == ActionType.STOP) {
task.setState(new TaskPaused());
} else if (actionType == ActionType.EXPIRE) {
task.setState(new TaskExpired());
}
}
}
// 具体状态任务暂停状态
class TaskPaused implements State {
@Override
public void update(Task task, ActionType actionType) {
if (actionType == ActionType.START) {
task.setState(new TaskOngoing());
} else if (actionType == ActionType.EXPIRE) {
task.setState(new TaskExpired());
}
}
}
// 具体状态任务完成状态
class TaskFinished implements State {
}
// 具体状态任务过期状态
class TaskExpired implements State {
}
//环境类
@Data
class Task {
private Long taskId;
// 初始化为初始态
private State state = new TaskInit();
// 更新状态
public void updateState(ActionType actionType) {
state.update(this, actionType);
}
}
经过状态模式处理后的任务类的耦合度得到降低,符合开闭原则。状态模式的优点在于符合单一职责原则,状态类职责明确,有利于程序的扩展。
观察者模式:指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式,它是对象行为型模式。观察者模式的主要角色如下。
-
抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。
-
具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。
-
抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
-
具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
// 抽象观察者
interface Observer {
void response(Long taskId); // 反应
}
// 抽象目标
abstract class Subject {
protected List<Observer> observers = new ArrayList<Observer>();
// 增加观察者方法
public void add(Observer observer) {
observers.add(observer);
}
// 删除观察者方法
public void remove(Observer observer) {
observers.remove(observer);
}
// 通知观察者方法
public void notifyObserver(Long taskId) {
for (Observer observer : observers) {
observer.response(taskId);
}
}
}
// 活动观察者
class ActivityObserver implements Observer {
private ActivityService activityService;
@Override
public void response(Long taskId) {
activityService.notifyFinished(taskId);
}
}
// 任务管理观察者
class TaskManageObserver implements Observer {
private TaskManager taskManager;
@Override
public void response(Long taskId) {
taskManager.release(taskId);
}
}
最后,将任务进行状态类优化成使用通用的通知方法,并在任务初始态执行状态流转时定义任务进行态所需的观察者:
// 任务进行状态
class TaskOngoing extends Subject implements State {
@Override
public void update(Task task, ActionType actionType) {
if (actionType == ActionType.ACHIEVE) {
task.setState(new TaskFinished());
// 通知
notifyObserver(task.getTaskId());
} else if (actionType == ActionType.STOP) {
task.setState(new TaskPaused());
} else if (actionType == ActionType.EXPIRE) {
task.setState(new TaskExpired());
}
}
}
// 任务初始状态
class TaskInit implements State {
@Override
public void update(Task task, ActionType actionType) {
if (actionType == ActionType.START) {
TaskOngoing taskOngoing = new TaskOngoing();
taskOngoing.add(new ActivityObserver());
taskOngoing.add(new TaskManageObserver());
task.setState(taskOngoing);
}
}
}
通过观察者模式让任务状态和通知方实现松耦合(分布式场景中使用消息队列(发布-订阅))。至此成功使用状态模式设计出了高内聚、高扩展性、单一职责的任务的整个状态机实现,以及做到松耦合的、符合依赖倒置原则的任务状态变更通知方式。
最后
以上就是小巧日记本为你收集整理的工作中常用到的设计模式-任务模型的设计的全部内容,希望文章能够帮你解决工作中常用到的设计模式-任务模型的设计所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复