1 OO設計原則
OO設計的五大原則
- 单一职责原则:就一个类而言,应该仅有一个引起他变化的原因。
- 开放封闭原则:实现开放封闭的核心思想就是对抽象编程,而不是对具体编程,因为抽象相对稳定。
- 依赖倒置原则:依赖抽象,不要依赖具体。
- 里氏代换原则:子类型必须能够替换到他们的父类型。主要着眼于对抽象和多态简历在继承的基础上
- 接口隔离原则:多个和客户相关的接口要好于一个通用接口
2 设计模式————策略模式
2.1 策略模式原理
分别封装行为接口,实现算法族,超类里放行为接口对象,在子类里放具体设定行为对象。
原则就是:分离变化部分,封装接口,基于接口编程实现各种功能。此模式让行为算法的变化独立于算法的使用者。
2.2 策略模式设计的代码分析————模拟鸭子项目
2.2.1 抽象出鸭子的行为,鸭子具有飞行能力和叫声,抽象出该接口
package com.fyzn12.api;
/**
* @author ZhangRongJun
* @version 1.0
* @date 2020/9/2 10:42
* @description:会飞的鸭子
*/
public interface FlyBehavior {
void fly();
}
package com.fyzn12.api;
/**
* @author ZhangRongJun
* @version 1.0
* @date 2020/9/2 10:43
* @description:叫声
*/
public interface QuackBehavior {
void quack();
}
2.2.2 对鸭子抽象出来的具体行为进行实现
/**
* @author ZhangRongJun
* @version 1.0
* @date 2020/9/2 10:51
* @description:会飞鸭子的实现
*/
public class GoodFlyBehavio implements FlyBehavior {
@Override
public void fly() {
System.out.println("会飞鸭子的实现");
}
}
/**
* @author ZhangRongJun
* @version 1.0
* @date 2020/9/2 10:52
* @description:叫声
*/
public class GaGaQuackBehavio implements QuackBehavior {
@Override
public void quack() {
System.out.println("叫声不同的体现");
}
}
2.2.3 对鸭子抽象总行为
/**
* @author ZhangRongJun
* @version 1.0
* @date 2020/9/2 10:44
* @description:定义鸭子的行为
*/
public abstract class Duck {
protected FlyBehavior flyBehavior;
protected QuackBehavior quackBehavior;
public Duck() {
}
public void fly() {
flyBehavior.fly();
}
public void quack() {
quackBehavior.quack();
}
public abstract void display();
}
2.2.3 对鸭子抽象总行为进行实现
/**
* @author ZhangRongJun
* @version 1.0
* @date 2020/9/2 10:47
* @description:环境角色
*/
public class GreenHeadDuck extends Duck {
public GreenHeadDuck() {
flyBehavior = new GoodFlyBehavio();
quackBehavior = new GaGaQuackBehavio();
}
@Override
public void display() {
fly();
quack();
}
public static void main(String[] args) {
GreenHeadDuck duck = new GreenHeadDuck();
duck.display();
}
}
2.3 策略模式的优缺点
优点:1. 算法可以自由切换;2. 避免使用多重条件判断;3. 扩展性好
缺点:1. 策略类会增多;2. 所有策略类都需要对外暴露
2.4 策略模式中有三个对象:
- 环境对象:该类中实现了对抽象策略中定义的接口或者抽象类的引用。
- 抽象策略对象:它可由接口或抽象类来实现。
- 具体策略对象:它封装了实现同不功能的不同算法。
2.5 策略模式的核心实现项目
2.5.1 定义一个事件,使用枚举类型进行包装
/**
* @author ZhangRongJun
* @version 1.0
* @date 2020/9/2 14:52
* @description:事件的定义
*/
public enum EventEnum {
ERROR("error", "异常中断"),
CLOSE("close", "正常关闭"),
LOGIN("login", "登录"),
HEALTHY("healthy", "健康监测");
private String value;
private String desc;
EventEnum(String value, String desc) {
this.value = value;
this.desc = desc;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
2.5.2 首先编写参数类、返回结果类
/**
* @author ZhangRongJun
* @version 1.0
* @date 2020/9/2 15:00
* @description:请求通用参数
*/
public class HandlerParam<T> {
/**
* @description:事件类型
*/
private EventEnum event;
/**
* @description:请求业务的参数
*/
private T param;
public HandlerParam(EventEnum event) {
this.event = event;
}
public HandlerParam(EventEnum event, T param) {
this.event = event;
this.param = param;
}
public EventEnum getEvent() {
return event;
}
public void setEvent(EventEnum event) {
this.event = event;
}
public T getParam() {
return param;
}
public void setParam(T param) {
this.param = param;
}
@Override
public String toString() {
return "HandlerParam{" +
"event=" + event +
", param=" + param +
'}';
}
}
该类包装了一个返回值事件EvenEnum以及请求参数类型 T
/**
* @author ZhangRongJun
* @version 1.0
* @date 2020/9/2 14:47
* @description:定义结果返回的类
*/
public class HandlerResult<T> {
/**
* 返回结果对象
*/
private T result;
public HandlerResult() {
}
/**
* @Param: result 返回结果的类型
* @description:TODO
* @Return
*/
public HandlerResult(T result) {
this.result = result;
}
public T getResult() {
return result;
}
public void setResult(T result) {
this.result = result;
}
@Override
public String toString() {
return "HandlerResult{" +
"result=" + result +
'}';
}
}
该类主要返回一个 T 的类型的返回值
2.5.3 编写抽象策略对象————抽象策略对象
/**
* @author ZhangRongJun
* @version 1.0
* @date 2020/9/2 14:44
* @description:定义业务处理方法和处理业务的类型。
*/
public abstract class AbstractHandler {
/**
* @Param: param
* @description:业务处理
* @Return
*/
public abstract HandlerResult strategy(HandlerParam param);
/**
* @Param:
* @description:返回业务类型,可以配置多个事件也可以是单个事件
* @Return
*/
public abstract List<EventEnum> eventTypes();
}
2.5.4 编写抽象策略对象的子类————具体策略对象
/**
* @author ZhangRongJun
* @version 1.0
* @date 2020/9/2 15:28
* @description:TODO
*/
@Component
public class LoginHandler extends AbstractHandler {
@Override
public HandlerResult strategy(HandlerParam param) {
//根据参数进行业务处理
System.out.println("业务处理");
//返回结果
return new HandlerResult<String>("业务处理完毕");
}
@Override
public List<EventEnum> eventTypes() {
return Arrays.asList(EventEnum.LOGIN, EventEnum.HEALTHY);
}
}
这里多个子类的区分主要是通过eventTypes方法中定义的集合区分
2.5.5 编写暴露接口————环境对象
/**
* @author ZhangRongJun
* @version 1.0
* @date 2020/9/2 15:13
* @description:暴露接口类
* 实现ApplicationContextAware接口,获取springboot的容器
*/
@Service
public class ContextHandlerService implements ApplicationContextAware {
/**
* 实现ApplicationContextAware接口获取springboot容器对象
* 方便创建完成对象后进行初始化
*/
private static final Map<EventEnum, AbstractHandler> HANDLER_MAP = new HashMap<>();
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/**
* @PostConstruct 声明在创建完成对象并且注入属性后执行该方法
*/
@PostConstruct
public void init() {
//获取AbstractHandler的所有实现类
Map<String, AbstractHandler> type = applicationContext.getBeansOfType(AbstractHandler.class);
for (Map.Entry<String, AbstractHandler> entry : type.entrySet()) {
//获取单个实现类
AbstractHandler value = entry.getValue();
if (value.eventTypes() == null) {
continue;
}
//或者注册事件
for (EventEnum eventEnum : value.eventTypes()) {
HANDLER_MAP.put(eventEnum, value);
}
}
}
/**
* @Param: param
* @description:业务处理类的路由方法
* @Return
*/
public HandlerResult strategy(HandlerParam param){
//这个位置会根据事件类型决定走那个决策类。
AbstractHandler abstractHandler = HANDLER_MAP.get(param.getEvent());
if (abstractHandler==null){
return null;
}
return abstractHandler.strategy(param);
}
}
2.5.6 编写测试类
/**
* @author ZhangRongJun
* @version 1.0
* @date 2020/9/2 15:30
* @description:TODO
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = StrategyTest.class)
@ComponentScan(basePackages = "com.fyzn12.service")
public class StrategyTest {
@Autowired
private ContextHandlerService service;
@Test
public void test() {
if (service==null){
System.out.println("空");
}
//定于路由参数即可
HandlerParam<String> param = new HandlerParam<>(EventEnum.HEALTHY, "我是参数");
System.out.println("请求参数:" + param);
HandlerResult result = service.strategy(param);
System.out.println("返回结果" + result);
}
}
这个位置值得注意的是,当测试类并不是在测试环境下时,要求加上@ComponentScan(basePackages = “com.fyzn12.service”)对暴露接口类的扫描,不然在注入private ContextHandlerService service时会提示找不到ContextHandlerService类。