OOP 七大原则
对扩展开放,对修改关闭。
继承必须确保超类(父类)所拥有的性质在子类中仍然成立。
要面向接口编程,而不是面向实现编程。
控制类的粒度大小、将对象解耦、提高其内聚性。
要为每个类建立它们需要的专用接口。
解耦,只与你的直接朋友交谈,不跟“陌生人”说话。
尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。
奖励的发放策略
假设现在要做一个营销,需要用户参与一个活动,然后完成一系列的任务,最后可以得到一些奖励作为回报。活动的奖励包含美团外卖、酒旅和美食等多种品类券,现在需要你帮忙设计一套奖励发放方案。
原始 Demo:
// 奖励服务
class RewardService {
// 外部服务
private WaimaiService waimaiService;
private HotelService hotelService;
private FoodService foodService;
// 使用对入参的条件判断进行发奖
public void issueReward(String rewardType, Object ... params) {
if ("Waimai".equals(rewardType)) {
WaimaiRequest request = new WaimaiRequest();
// 构建入参
request.setWaimaiReq(params);
waimaiService.issueWaimai(request);
} else if ("Hotel".equals(rewardType)) {
HotelRequest request = new HotelRequest();
request.addHotelReq(params);
hotelService.sendPrize(request);
} else if ("Food".equals(rewardType)) {
FoodRequest request = new FoodRequest(params);
foodService.getCoupon(request);
} else {
throw new IllegalArgumentException("rewardType error!");
}
}
}
存在问题:
使用策略模式 & 适配器模式来优化
策略模式
定义了一系列的算法,并将每一个算法封装起来,使它们可以相互替换;
策略模式通常包含以下角色:
适配器模式
将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作;
适配器模式包含以下主要角色:
优化 Demo:
// 策略接口
interface Strategy {
void issue(Object ... params);
}
// 外卖策略
class Waimai implements Strategy {
private WaimaiService waimaiService;
@Override
public void issue(Object... params) {
WaimaiRequest request = new WaimaiRequest();
// 构建入参
request.setWaimaiReq(params);
waimaiService.issueWaimai(request);
}
}
// 酒旅策略
class Hotel implements Strategy {
private HotelService hotelService;
@Override
public void issue(Object... params) {
HotelRequest request = new HotelRequest();
request.addHotelReq(params);
hotelService.sendPrize(request);
}
}
// 美食策略
class Food implements Strategy {
private FoodService foodService;
@Override
public void issue(Object... params) {
FoodRequest request = new FoodRequest(params);
foodService.payCoupon(request);
}
}
// 使用分支判断获取的策略上下文
class StrategyContext {
public static Strategy getStrategy(String rewardType) {
switch (rewardType) {
case "Waimai":
return new Waimai();
case "Hotel":
return new Hotel();
case "Food":
return new Food();
default:
throw new IllegalArgumentException("rewardType error!");
}
}
}
// 优化后的策略服务
class RewardService {
public void issueReward(String rewardType, Object ... params) {
Strategy strategy = StrategyContext.getStrategy(rewardType);
strategy.issue(params);
}
}
代码耦合度降低,但仍存在以下问题:
使用单例模式来优化
单例模式
// 策略接口
interface Strategy {
void issue(Object ... params);
}
// 策略上下文, 用于管理策略的注册和获取
class StrategyContext {
private static final Map<String, Strategy> registerMap = new HashMap<>();
// 注册策略
public static void registerStrategy(String rewardType, Strategy strategy) {
registerMap.putIfAbsent(rewardType, strategy);
}
// 获取策略
public static Strategy getStrategy(String rewardType) {
return registerMap.get(rewardType);
}
}
// 抽象策略类
abstract class AbstractStrategy implements Strategy {
// 类注册方法
public void register() {
StrategyContext.registerStrategy(getClass().getSimpleName(), this);
}
}
// 单例外卖策略
class Waimai extends AbstractStrategy implements Strategy {
private static final Waimai instance = new Waimai();
private WaimaiService waimaiService;
private Waimai() {
register();
}
public static Waimai getInstance() {
return instance;
}
@Override
public void issue(Object... params) {
WaimaiRequest request = new WaimaiRequest();
// 构建入参
request.setWaimaiReq(params);
waimaiService.issueWaimai(request);
}
}
// 单例酒旅策略
class Hotel extends AbstractStrategy implements Strategy {
private static final Hotel instance = new Hotel();
private HotelService hotelService;
private Hotel() {
register();
}
public static Hotel getInstance() {
return instance;
}
@Override
public void issue(Object... params) {
HotelRequest request = new HotelRequest();
request.addHotelReq(params);
hotelService.sendPrize(request);
}
}
// 单例美食策略
class Food extends AbstractStrategy implements Strategy {
private static final Food instance = new Food();
private FoodService foodService;
private Food() {
register();
}
public static Food getInstance() {
return instance;
}
@Override
public void issue(Object... params) {
FoodRequest request = new FoodRequest(params);
foodService.payCoupon(request);
}
}
Strategy strategy = StrategyContext.getStrategy("Waimai");
strategy.issue("外卖详情参数");
// Waimai waimai = Waimai.getInstance();
// waimai.issue("外卖详情参数");
任务模型的设计
完成任务模型的设计。你需要重点关注状态的流转变更,以及状态变更后的消息通知。
原始 Demo:
// 任务状态枚举
@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;
}
}
}
}
存在问题:
使用状态模式 & 观察者模式来优化
状态模式
对有状态的对象,把复杂的「判断逻辑」提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为;
状态模式包含以下主要角色:
观察者模式
指多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作「发布-订阅」模式、「模型-视图」模式,它是对象行为型模式;
观察者模式的主要角色如下:
// 任务状态枚举
@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;
}
// 任务状态抽象接口
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 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);
}
}
}
// 任务进行状态
// 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 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 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);
}
}
// 抽象观察者
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);
}
}
活动的迭代重构
之前设计开发了活动模型,现在我们需要在任务型活动的参与方法上增加一层风险控制。
原始 Demo:
// 抽象活动接口
interface ActivityInterface {
void participate(Long userId);
}
// 活动类
class Activity implements ActivityInterface {
private String type;
private Long id;
private String name;
private Integer scene;
private String material;
public Activity(String type) {
this.type = type;
// id的构建部分依赖于活动的type
if ("period".equals(type)) {
id = 0L;
}
}
public Activity(String type, Long id) {
this.type = type;
this.id = id;
}
public Activity(String type, Long id, Integer scene) {
this.type = type;
this.id = id;
this.scene = scene;
}
public Activity(String type, String name, Integer scene, String material) {
this.type = type;
this.scene = scene;
this.material = material;
// name的构建完全依赖于活动的type
if ("period".equals(type)) {
this.id = 0L;
this.name = "period" + name;
} else {
this.name = "normal" + name;
}
}
// 参与活动
@Override
public void participate(Long userId) {
// do nothing
}
}
// 任务型活动
class TaskActivity extends Activity {
private Task task;
public TaskActivity(String type, String name, Integer scene, String material, Task task) {
super(type, name, scene, material);
this.task = task;
}
// 参与任务型活动
@Override
public void participate(Long userId) {
// 更新任务状态为进行中
task.getState().update(task, ActionType.START);
}
}
使用建造者模式来优化
建造者模式
指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示。它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的;
建造者模式的主要角色如下:
装饰器模式
指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式;
装饰器模式主要包含以下角色:
// 抽象活动接口
interface ActivityInterface {
void participate(Long userId);
}
// 活动类
class Activity implements ActivityInterface {
protected String type;
protected Long id;
protected String name;
protected Integer scene;
protected String material;
// 全参构造函数
public Activity(String type, Long id, String name, Integer scene, String material) {
this.type = type;
this.id = id;
this.name = name;
this.scene = scene;
this.material = material;
}
@Override
public void participate(Long userId) {
// do nothing
}
// 静态建造器类, 使用奇异递归模板模式允许继承并返回继承建造器类
public static class Builder<T extends Builder<T>> {
protected String type;
protected Long id;
protected String name;
protected Integer scene;
protected String material;
public T setType(String type) {
this.type = type;
return (T) this;
}
public T setId(Long id) {
this.id = id;
return (T) this;
}
public T setId() {
if ("period".equals(this.type)) {
this.id = 0L;
}
return (T) this;
}
public T setScene(Integer scene) {
this.scene = scene;
return (T) this;
}
public T setMaterial(String material) {
this.material = material;
return (T) this;
}
public T setName(String name) {
if ("period".equals(this.type)) {
this.name = "period" + name;
} else {
this.name = "normal" + name;
}
return (T) this;
}
public Activity build(){
return new Activity(type, id, name, scene, material);
}
}
}
// 任务型活动
class TaskActivity extends Activity {
protected Task task;
// 全参构造函数
public TaskActivity(String type, Long id, String name, Integer scene, String material, Task task) {
super(type, id, name, scene, material);
this.task = task;
}
// 参与任务型活动
@Override
public void participate(Long userId) {
// 更新任务状态为进行中
task.getState().update(task, ActionType.START);
}
// public void participate(Long userId) {
// // 对目标用户做风险控制, 失败则抛出异常
// Risk.doControl(userId);
// // 更新任务状态为进行中
// task.state.update(task, ActionType.START);
// }
// 继承建造器类
public static class Builder extends Activity.Builder<Builder> {
private Task task;
public Builder setTask(Task task) {
this.task = task;
return this;
}
public TaskActivity build(){
return new TaskActivity(type, id, name, scene, material, task);
}
}
}
// 抽象装饰角色
abstract class ActivityDecorator implements ActivityInterface {
protected ActivityInterface activity;
public ActivityDecorator(ActivityInterface activity) {
this.activity = activity;
}
public abstract void participate(Long userId);
}
// 能够对活动做风险控制的包装类
class RiskControlDecorator extends ActivityDecorator {
public RiskControlDecorator(ActivityInterface activity) {
super(activity);
}
@Override
public void participate(Long userId) {
// 对目标用户做风险控制,失败则抛出异常
Risk.doControl(userId);
// 更新任务状态为进行中
activity.participate(userId);
}
}
TaskActivity taskActivity = new TaskActivity( /* ... */ );
// 对TaskActivity对象进行风险控制包装
ActivityInterface wrappedTaskActivity = new RiskControlDecorator(taskActivity);
wrappedTaskActivity.participate(userId);
参考资料