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 策略模式中有三个对象:

  1. 环境对象:该类中实现了对抽象策略中定义的接口或者抽象类的引用。
  2. 抽象策略对象:它可由接口或抽象类来实现。
  3. 具体策略对象:它封装了实现同不功能的不同算法。

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类。