【Head First 设计模式】-- 策略模式

news2024/11/27 20:30:50

一、背景
Head First 设计模式第一章设计模式入门–策略模式

二、工具箱的工具(本章)
1、OO基础
封装
继承
多态
抽象
2、OO原则
封装变化
面向接口编程,而非面向实现编程
组合优于继承
3、OO模式
策略模式,所谓策略模式就是定义算法族并将其分别封装起来,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。

算法族:白话讲就是一个对象的一组行为,但是我们通常将一组行为称之为“一族算法”。

三、例子展示
《Head First设计模式》使用鸭子举例,从一开始简单的封装实现鸭子游泳、叫的行为,到后来行为的添加之后导致现有设计的弹性不足(可复用、可扩展、可维护能力大大折扣),作者将OO基础&原则结合起来,设计一个应对鸭子行为添加时弹性较大的系统,这种模式称之为策略模式。

1、初期的鸭子系统
a.UML图
在这里插入图片描述

鸭子有游泳、叫以及展示自己品种的能力,Duck超类将swim() & quack()实现了,供子类直接调用,展示品种定义为抽象方法供子类去实现。早期看起来,采用继承的方式设计好像是没有问题的。

思考一下,当出现下面场景时现有的设计还是否合理?

如果产品要求有的鸭子是会飞的
如果产品要求并不是所有的鸭子都会叫,并且会叫的鸭子叫的方式也有可能不同
2、中期的鸭子系统
a.UML图
在这里插入图片描述

首先考虑利用接口定义行为,特殊的鸭子实现特定的接口,来达到具备某种能力的目的。这种方案,看似可行,其实对于代码的可复用性是打击性的。例如,此次需求需要实现几十种会飞的鸭子,那么我们就需要实现几十次的fly方法,这个系统几乎没有复用,成本是非常高的。

3、最终的鸭子系统
a.UML图
在这里插入图片描述

b.如何设计?
根据前面提到的设计原则:

封装变化:我们将飞行行为与呱呱叫行为都独立出来并进行了封装
面向接口编程而非实现:在Duck中,我们声明了两个变量(flyBehavior & quackBehavior),定义了两个set方法用于修改这两个变量,变量的实例是什么我不关心,我只关心我能够调用它的fly or quack这样的关键方法就行,这些方法具体是如何实现的我就不关心了
组合优于继承:在第二条中提到声明了两个变量,也就是两个变化的行为,Duck与这两个行为之间的关系是Has-a,而不是Is-a,有时候“有一个”比“是一个”更好
c.模式
而最终的这个系统运用的就是策略模式,它将算法族与使用算法的客户独立开来,可以相互替换(我可以在运行时让鸭子会叫,也可以让它不会叫)

四、代码

  1. Duck相关
    a.Duck
package com.markus.designpatterns.chapter1.duck;

import com.markus.designpatterns.chapter1.behavior.FlyBehavior;
import com.markus.designpatterns.chapter1.behavior.QuackBehavior;
import com.markus.designpatterns.chapter1.behavior.concrete.FlyNoWay;
import com.markus.designpatterns.chapter1.behavior.concrete.MuteQuack;

public abstract class Duck {
  private FlyBehavior flyBehavior;
  private QuackBehavior quackBehavior;

  public Duck() {
    // 默认鸭子不会飞 & 不会叫
    this.flyBehavior = new FlyNoWay();
    this.quackBehavior = new MuteQuack();
  }

  public void swim() {
    System.out.println("I can swim!");
  }

  abstract public void display();

  public void performFly(){
    flyBehavior.fly();
  }

  public void performQuack(){
    quackBehavior.quack();
  }

  public void setFlyBehavior(FlyBehavior flyBehavior) {
    this.flyBehavior = flyBehavior;
  }

  public void setQuackBehavior(QuackBehavior quackBehavior) {
    this.quackBehavior = quackBehavior;
  }
}

b.Duck子类

public class DecoyDuck extends Duck{
  @Override
  public void display() {
    System.out.println("I am a Decoy Duck!");
  }
}
public class MallardDuck extends Duck{
  @Override
  public void display() {
    System.out.println("I am a mallard duck!");
  }
}
public class RedheadDuck extends Duck{
  @Override
  public void display() {
    System.out.println("I am a Redhead Duck!");
  }
}
public class RubberDuck extends Duck{
  @Override
  public void display() {
    System.out.println("I am a Rubber Duck!");
  }
}

2、行为相关
a.Fly

public interface FlyBehavior {
  void fly();
}
public class FlyNoWay implements FlyBehavior {
  @Override
  public void fly() {

  }
}
public class FlyWithWings implements FlyBehavior {
  @Override
  public void fly() {
    System.out.println("I have wings, so I can fly!");
  }
}

b.Quack

public interface QuackBehavior {
  void quack();
}
public class MuteQuack implements QuackBehavior {
  @Override
  public void quack() {

  }
}
public class Quack implements QuackBehavior {
  @Override
  public void quack() {
    System.out.println("quack");
  }
}
public class Squeak implements QuackBehavior {
  @Override
  public void quack() {
    System.out.println("squeak");
  }
}

3、测试Demo

public class DuckDisplayDemo {
  public static void main(String[] args) {
    Duck duck = new RedheadDuck();
    duck.display();
    duck.swim();
    //默认状态下不会飞、不会叫
    duck.performFly();
    duck.performQuack();
    System.out.println();
    //进行手动赋能
    duck.setFlyBehavior(new FlyWithWings());
    duck.performFly();
    duck.setQuackBehavior(new Quack());
    duck.performQuack();
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1175156.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于STM32HAL库(窗口看门狗)-简述

目录 概述 一、开发环境 二、STM32CubeMx配置 三、编码 四、运行结果 五、总结 概述 一个成熟靠谱的项目,离不开“看门狗”的必选项,凡是人写的程序多少都会有出现bug的情况(或芯片外设受外界干扰导致故障程序卡死、跑飞的情况&#xf…

中国多主数据库:压强投入,期待破茧

拿破仑曾说:“战争的艺术就是在某一点上集中最大优势兵力”,强调了力量集中的重要性。 如今,国际形势风云变幻,西方世界对中国的围剿不再仅仅体现在军事和地缘政治上,而更多表现在经济与科技上。在科技领域&#xff0…

小程序制作(超详解!!!)第十二节 循环求和计算器

1.index.wxml <view class"box"><view class"title">利用循环语句求和</view><view><input placeholder"请输入起点数值" type"number" bindblur"starNum"></input><!--一旦失去交…

JavaEE-部署项目到服务器

本部分内容为&#xff1a;安装依赖&#xff1a;JDK&#xff0c;Tomcat&#xff0c;Mysql&#xff1b;部署项目到服务器 什么是Tomcat Tomcat简单的说就是一个运行JAVA的网络服务器&#xff0c;底层是Socket的一个程序&#xff0c;它也是JSP和Serlvet的一个容器。 为什么我们需要…

【Docker】Docker中 的AUFS、BTRFS、ZFS、存储池概念的详细讲解

前言 作者简介&#xff1a; 辭七七&#xff0c;目前大二&#xff0c;正在学习C/C&#xff0c;Java&#xff0c;Python等 作者主页&#xff1a; 七七的个人主页 文章收录专栏&#xff1a; 七七的闲谈 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&…

Jetpack:030-Jetpack中的状态

文章目录 1. 概念介绍2. 使用方法2.1 可监听对象2.2 获取状态值2.3 修改状态值2.4 重组函数 3. 示例代码4. 内容总结 我们在上一章回中介绍了Jetpack中网格布局相关的内容&#xff0c;本章回中主要 介绍状态。闲话休提&#xff0c;让我们一起Talk Android Jetpack吧&#xff0…

好题分析(2023.10.29——2023.11.04)

目录 ​编辑 前情回顾&#xff1a; 前言&#xff1a; 题目一&#xff1a;《合并两个有序数组》 1.运用qsort 2.利用三指针 题目二&#xff1a;《移除链表元素》 题目三&#xff1a;《链表的中间节点》 总结&#xff1a; 前情回顾&#xff1a; 我们在上一篇好题分析…

【图】:常用图搜索(图遍历)算法

目录 概念图遍历深度优先搜索 (DFS)DFS 适用场景DFS 优缺点 广度优先搜索 (BFS)BFS 适用场景BFS 优缺点 DFS & BFS 异同点 图搜索Dijkstra算法A*算法Floyd算法Bellman-Ford算法SPFA算法 概念 图遍历和图搜索是解决图论问题时常用的两种基本操作。 图遍历是指从图中的某一个…

Spring Cloud分布式缓存

目录 单点Redis Redis数据持久化 RDB持久化 bgsave细节 RDB的缺点 AOF持久化 AOF的问题 RDB与AOF对比 搭建Redis主从架构 数据同步原理 全量同步 增量同步 主从同步优化 Redis哨兵 集群检测 选举主节点 故障转移 搭建哨兵集群 RedisTemplate的哨兵模式 单点…

【Leetcode】【每日一题】【中等】187. 重复的DNA序列 官方题解待更新

力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能&#xff0c;轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/repeated-dna-sequences/descrip…

C++ AVL树 c语言版本

引入平衡树 假设我们有两个节点&#xff1a;当我们插入第三个节点&#xff0c;就失衡了&#xff1a;此刻我们就要把它平衡一下。 为什么要变平衡 为什么说它失衡了呢&#xff0c;又为什么要把它变平衡&#xff1f; 如图a&#xff0c;假设我们要查找30这个节点就要查3次才能…

耳机,耳麦,傻傻分不清,难怪麦克风没有声音

有时候会发现为什么同一根耳机线&#xff0c;插到笔记本上可以同时说话和收音&#xff0c;但是插到台式机就不行呢&#xff1f; 因为在以前&#xff0c;耳机和麦克风的接口都是独立的&#xff08;如上图&#xff09;。现在笔记本为了方便&#xff0c;就普遍使用了二合一接口&a…

正点原子嵌入式linux驱动开发——Linux 网络设备驱动

网络驱动是linux里面驱动三巨头之一&#xff0c;linux下的网络功能非常强大&#xff0c;嵌入式linux中也常常用到网络功能。前面已经讲过了字符设备驱动和块设备驱动&#xff0c;本章就来学习一下linux里面的网络设备驱动。 嵌入式网络简介 嵌入式下的网络硬件接口 本次笔记…

是时候放弃 Java 序列化了

基本概念 Java 序列化和反序列化三连问&#xff1a; 什么是 Java 序列化和反序列化&#xff1f;为什么需要 Java 序列化和反序列化&#xff1f;如何实现 Java 序列化和反序列化&#xff1f; 是什么 一句话就能够说明白什么是 Java 序列化和反序列化&#xff1f;Java 序列化…

【探索Linux】—— 强大的命令行工具 P.13(文件系统 | 软硬链接 | 动态库和静态库)

阅读导航 引言一、文件系统1. 磁盘文件系统2. 磁盘结构&#xff08;1&#xff09;物理结构&#xff08;2&#xff09;存储结构 3. stat 命令4. Linux ext2文件系统 二、软硬链接1. 软连接2. 硬链接 三、动态库和静态库1. 动态库&#xff08;1&#xff09;动态库文件扩展名&…

计算虚拟化1——CPU虚拟化

目录 vCPU的概念 vCPU和CPU的关系 CPU的Ring级别 CPU虚拟化技术 软件辅助全虚拟化 半虚拟化 硬件辅助虚拟化 计算资源的虚拟化可以分为CPU虚拟化、内存虚拟化、I/O虚拟化三个方面 CPU虚拟化&#xff1a;多个虚拟机共享CPU资源&#xff0c;对虚拟机中的敏感指令进行截获…

【JavaSE】基础笔记 - 类和对象(上)

目录 1、面向对象的初步认知 1.1、什么是面向对象 1.2、面向对象与面向过程 2. 类定义和使用 2.1、简单认识类 2.2、类的定义格式 2.3、自定义类举例说明 2.3.1、定义一个狗类 2.3.2、定义一个学生类 3、类的实例化 3.1、什么是实例化 3.2、类和对象的说明 1、面向…

MySQL性能优化的最佳20条经验

概述 关于数据库的性能&#xff0c;这并不只是DBA才需要担心的事。当我们去设计数据库表结构&#xff0c;对操作数据库时(尤其是查表时的SQL语句)&#xff0c;我们都需要注意数据操作的性能。下面讲下MySQL性能优化的一些点。 1. 为查询缓存优化你的查询 大多数的MySQL服务器…

Python基础入门例程47-NP47 牛牛的绩点(条件语句)

最近的博文&#xff1a; Python基础入门例程46-NP46 菜品的价格&#xff08;条件语句&#xff09;-CSDN博客 Python基础入门例程45-NP45 禁止重复注册&#xff08;条件语句&#xff09;-CSDN博客 Python基础入门例程44-NP44 判断列表是否为空&#xff08;条件语句&#xff0…

ElasticSearch 实现 全文检索 支持(PDF、TXT、Word、HTML等文件)通过 ingest-attachment 插件实现 文档的检索

一、Attachment 介绍 Attachment 插件是 Elasticsearch 中的一种插件&#xff0c;允许将各种二进制文件&#xff08;如PDF、Word文档等&#xff09;以及它们的内容索引到 Elasticsearch 中。插件使用 Apache Tika 库来解析和提取二进制文件的内容。通过使用 Attachment 插件&a…