• 当涉及到“维护”时,为了“复用”目的而使用继承,结局并不完美 P4

    • 对父类代码进行修改时,影响层面可能会很大

思考题

利用继承来提供 Duck 的行为,这会导致下列哪些缺点?(多选) P5

  • [ ] A. 代码在多个子类中重复

    • 使用继承就是为了复用代码
    • 【答案有此选项】从另一方面考虑,也有这个缺点,比如:多个子类都存在相同的实现,但又与父类的实现不同
  • [x] B. 运行时的行为不容易改变
    • 编译完成后,各种行为已经确定,无法再继续修改(第一次看没有选择,看完策略模式后又觉得有这个缺点)
  • [ ] C. 我们不能让鸭子跳舞
    • 在父类中写 dance() 的方法即可
  • [x] D. 很难知道所有鸭子的全部行为
    • 子类可以覆盖父类的方法,所以不知道子类的具体行为
  • [ ] E. 鸭子不能同时又飞又叫
    • 在父类中写 flyAndQuack() 即可
  • [x] F. 改变会牵一发而动全身,造成其他鸭子不想要的改变
    • 在父类 Duck 中增加 fly() 方法,就会使得所有的子类鸭子都会飞,包括不会飞的橡皮鸭

使用接口方式的优缺点 P6

优点
  • 可以避免继承时的出现有不应具有的的行为而大量覆盖
  • 在 Java8 中可以用默认方法实现和继承效果一样的代码复用
缺点
  • 某一行为在子类中都具有,却有不同实现时,仍然有代码重复的问题
  • 在获取到父类时,必须得先用 instanceof 判断是否实现某接口,才能转换类型使用相关方法

思考题

驱动改变的因素很多。找出你的应用中需要改变代码的原因,一一列出来 P8

  • 我们的顾客或用户需要别的东西,或者想要新功能
  • 我的公司决定采用别的数据产品,又从另一家厂商买了数据,这造成数据格式不兼容
  • 重构
  • 性能优化
  • 修复BUG、安全问题

设计原则

取出并封装变化的部分,让其他部分不会受到影响 P9

  • 减少改变代码带来的影响
  • 便于修改和扩充,更具有弹性

设计原则

针对接口编程,而不是针对实现编程 P11

  • 可以在运行时动态改变实现
“针对接口编程”即“针对超类型 (supertype) 编程” P12
  • 接口既指一种“概念”,也指 Java 的 interface

设计原则

多用组合,少用继承 P23

  • 组合具有弹性,可以动态改变实现

策略模式

定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户 P24

  • 其实没学的时候也经常凭借经验不知不觉中使用到了策略模式,比如:不同字段的校验逻辑、不同推荐策略、不同车型匹配逻辑等等。
  • 策略模式在 Java 源码中可以说随处可见,比如 ThreadPoolExecutor 中的 RejectedExecutionHandler 就是策略,用来进行拒绝新任务。可以在初始化线程池的时候可以设置相应的四种拒绝策略中的一种以满足不同的需要
    private volatile RejectedExecutionHandler handler;

    // RejectedExecutionHandler 接口定义
public interface RejectedExecutionHandler {
void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}
  • 刚开始看到策略模式和观察者模式的时候,感觉两者差不多(或者说是观察者模式自带策略模式)。后来有仔细思考了一下, 两者的区别主要还是在使用场景上。策略模式主要是调用策略的一方想通过这个策略完成自己所需要的功能,一般每次只有一种策略;观察者模式主要是主题想通知观察者使观察者完成自己的功能,可以存在多个不同的观察者

良好的OO设计具备的特性 P32

  • 可复用
  • 可扩充
  • 可维护

所思所想

  • 经验和实战的作用还是挺大的,一直在潜移默化地影响代码风格和思考方式
  • 系统地学习相关知识,可以使自己思考更全面,从思考架构的层次提高到模式层面
  • 平时写代码时也总会想到哪些地方需要变化,并进行一定的处理;这是个好习惯,要继续坚持,但也要保证尽快开始第一步(或者边实现边设计),防止设计很久,却在实现时发现很多地方不适用的情况发生
  • 很多时候从不同方面考虑问题时,得到的答案并不一样,要有辩证思维

本文首发于公众号:满赋诸机(点击查看原文) 开源在 GitHub :reading-notes/head-first-design-patterns

Head First 设计模式 - 01. 策略 (Strategy) 模式的更多相关文章

  1. C++设计模式实现--策略(Strategy)模式

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/L_Andy/article/details/30489331 一. 举例说明 曾经做了一个程序,程序 ...

  2. 策略(strategy)模式

    Head First一书中对于策略(strategy)模式的正式定义是:策略模式定义了算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户. 为了介绍这个算法,书中讲了 ...

  3. Java 实现策略(Strategy)模式

    策略模式:行为型模式 将同一行为,不同的处理算法分别封装起来.让它们之间能够互相替换 1. 定义一个超类型接口,及 行为方法 2. 定义不同的实现类,实现该行为的 不同的算法 /** * 策略模式:针 ...

  4. 设计模式C++实现(1)——策略(Strategy)模式

    目录 策略模式 应用案例 实现的关键 Talk is cheap,let's See The Code 设计思想 参考 策略模式 策略模式定义了一系列算法和行为(也就是策略),他们可以在运行时相互替换 ...

  5. c#设计模式之策略者模式(Strategy Pattern)

    场景出发 假设存在如下游戏场景: 1:角色可以装备木剑,铁剑,魔剑3种装备,分别对怪物造成20HP,50HP,100HP伤害(未佩戴装备则无法攻击); 2角色可以向怪物攻击,一次攻击后损失角色所佩戴装 ...

  6. C#设计模式(20)——策略者模式(Stragety Pattern)

    一.引言 前面主题介绍的状态模式是对某个对象状态的抽象,而本文要介绍的策略模式也就是对策略进行抽象,策略的意思就是方法,所以也就是对方法的抽象,下面具体分享下我对策略模式的理解. 二.策略者模式介绍 ...

  7. HeadFirst设计模式(一)策略者模式

    最近在看HeadFirst设计模式一书,作为一个半路出家的程序员,感觉很多东西需要学习,学习的路程中有些东西学了当时觉得理解了,但日常工作中没有使用到渐渐的自己就忘记了.--------------- ...

  8. 设计模式C++描述----15.策略(Strategy)模式

    一. 举例说明 以前做了一个程序,程序的功能是评价几种加密算法时间,程序的使用操作不怎么变,变的是选用各种算法. 结构如下: Algorithm:抽象类,提供算法的公共接口. RSA_Algorith ...

  9. 《Head First 设计模式》ch.1 策略(Strategy)模式

    策略模式 定义了算法族,分别封装起来,让它们可以互相替换,让算法的变化独立于使用算法的客户. 模式名词的意义 威力强大,交流的不止是模式名称,而是一整套模式背后所象征的质量.特性.约束 用更少的词汇做 ...

随机推荐

  1. Python中使用“模块名.__all__”查看模块建议导出的属性

    在<第10.5节 使用__all__定义Python模块导入白名单>中,老猿介绍了在自定义模块中使用定义__all__属性来提供模块对外可见的白名单,使用该机制除了可以定义访问的白名单外, ...

  2. 由Java 15废弃偏向锁,谈谈Java Synchronized 的锁机制

    Java 15 废弃偏向锁 JDK 15已经在2020年9月15日发布,详情见 JDK 15 官方计划.其中有一项更新是废弃偏向锁,官方的详细说明在:JEP 374: Disable and Depr ...

  3. Day5 Scrum 冲刺博客

    一.站立式会议# 1. 会议照片 2. 工作进度+燃尽图 团队成员 昨日完成工作 今日工作计划 遇到的困难 周梓波 将方块分类并抽象成类 将方块旋转变形 逻辑漏洞较多 纪昂学 绘制游戏背景,方块,状态 ...

  4. 中间件面试专题:kafka高频面试问题

  5. Java IO源码分析(三)——PipedOutputStream和PipedInputStream

    简介 PipedOutputStream和PipedInputStream主要用于线程之间的通信 .二者必须配合使用,也就是一段写入,另一端接收.本质上也是一个中间缓存区,讲数据缓存在PipedInp ...

  6. Java并发编程的艺术(一)——并发编程的注意问题

    并发编程是为了使程序运行得更快,但是,不是启动更多得线程就能最大限度地执行并发,也不是线程更多就能使得程序运行得更快,而且并发编程更容易产生错误,如果要高效且正确地执行并发,就需要注意这三种问题 上下 ...

  7. STL—— 容器(vector)begin() 与 rbegin() , end() 与 rend()

    1. Vector 迭代器首地址与尾地址 begin() 和 end() 在代码中可以将迭代器用作参数的位置可以使用  begin() 和 end() 获取地址,如下代码: 1 #include &l ...

  8. C++ 虚函数表与多态 —— 多重继承的虚函数表 & 内存布局

    多重继承的虚函数表会有两个虚表指针,分别指向两个虚函数表,如下代码中的 vptr_s_1.vptr_s_2,Son类继承自 Father 和 Mather 类,并且改写了 Father::func_1 ...

  9. 【ubantu 安装Jmeter和Jdk环境】

    Linux环境安装Java(含安装包下载地址) 一定要使用有权限的用户 1.下载JDK压缩包,下载地址:https://blog.csdn.net/duketyson2009/article/deta ...

  10. SpringBoot + Layui + JustAuth +Mybatis-plus实现可第三方登录的简单后台管理系统

    1. 简介   在之前博客:SpringBoot基于JustAuth实现第三方授权登录 和 SpringBoot + Layui +Mybatis-plus实现简单后台管理系统(内置安全过滤器)上改造 ...