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

news2024/11/26 2:24:13

一、背景
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/1173483.html

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

相关文章

UE4 Niagara Module Script 初次使用笔记

这里可以创建一个Niagara模块脚本 创建出来长这样 点击号,输出staticmesh,点击它 这样就可以拿到对应的一些模型信息 这里的RandomnTriCoord是模型的坐标信息 根据坐标信息拿到位置信息 最后的Position也是通过Map Set的号,选择Particles的P…

2023年【安全员-A证】新版试题及安全员-A证模拟考试题库

题库来源:安全生产模拟考试一点通公众号小程序 安全员-A证新版试题考前必练!安全生产模拟考试一点通每个月更新安全员-A证模拟考试题库题目及答案!多做几遍,其实通过安全员-A证理论考试很简单。 1、【多选题】《中华人民共和国工…

Win11新电脑启动无无线网络连接解决办法

Win11新电脑启动无无线网络连接解决办法 前言一、解决方法 前言 今天笔者在使用学校实验室分配的新电脑时候,发现在新激活的时候需要让我连接到无线网络,但不管鼠标怎么点都操作不了,于是在卡在这里了,唯一的办法就是跳过此页面&…

vCenter挂载iSCSI共享存储

1.添加磁盘,创建新的物理卷 Volumes -> (Volumes section)Manage Volumes ->create new physical volumes -> (Block Device Management) 2.点击新磁盘 3.新建物理卷 Volumes -> (Volumes section)Block Devices -> (Block Device Management)/de…

CSAPP BOMB LAB part3

CSAPP BOMB LAB part3 phase_4 bomb.s phase_4的代码: 格式: 40102e行,比较0x8rsp的值和0xe, 需要让0x8rsp小于0xe, 然后跳转到40103a, func函数根据bomb.s 转化为c代码: 这个直接参考了知乎网友的翻译, func4的返回值等于0, 跳转到40…

AI 绘画 | Stable Diffusion 提示词

Prompts提示词简介 在Stable Diffusion中,Prompts是控制模型生成图像的关键输入参数。它们是一种文本提示,告诉模型应该生成什么样的图像。 Prompts可以是任何文本输入,包括描述图像的文本,如“一只橘色的短毛猫,坐在…

【4步精确手册】帮助你快速掌握国外纳斯达克大屏营销推广!

纳斯达克(Nasdaq)是美国著名的证交所之一,它是以高科技企业的上市闻名世界。纳斯达克大屏营销推广指的是在纳斯达克交易中心大型屏上展现广告、宣传信息的一种营销推广方式。下面我们就为大家介绍一下如何用四个简易流程把握国外纳斯达克大屏…

怎么在markdown中设置字体颜色为红色

2023年11月5日,周日上午 除了使用HTML标签,Markdown还提供了一种更简洁的方式来设置文本样式,包括颜色。 所有,可以使用Markdown的扩展语法来实现。 具体来说,可以使用以下语法来输出红色字体的字: 这是…

【JavaSE语法】类和对象(一)

一、面向对象的初步认知 1.1 什么是面向对象 Java是一门纯面向对象的语言(Object Oriented Program,简称OOP),在面向对象的世界里,一切皆为对象。面向对象是解决问题的一种思想,主要依靠对象之间的交互完成一件事情 …

心理咨询服务预约小程序的效果如何

心理咨询机构很多,随着人们生活压力提升及生活多样化,部分人群在心理方面可能会面对各种不适,因此寻找心理咨询机构成为优先选项。 对商家来说,市场中拥有很多需求客户,且具备跨区域服务性,传统线下引流拓…

一文读懂ARM安全性架构和可信系统构建要素

一文读懂ARM安全性架构和可信系统构建要素 所谓可信系统(trusted system),即能够用于保护密码和加密密钥等资产(assets)免受一系列的可信攻击,防止其被复制、损坏或不可用(unavailable&#xf…

宠物医院服务预约小程序的效果如何

随着养宠家庭增多及对爱宠的照顾加深,除了食品、服饰外,宠物医院近些年也迎来了较高发展,部分城市甚至聚集着众多品牌,以单店或多店品牌的方式拓展市场。 对宠物医院来说,一般都是拓展同市客户,或者多门店…

【漏洞复现】​金蝶云星空管理中心

目录 0x01 漏洞介绍 0x02 影响产品 0x03 语法特征 0x04 漏洞复现 0x01 漏洞介绍 金蝶云星空是一款基于领先的可组装低代码PaaS平台,全面服务客户研发、生产、营销、供应链、财务等领域转型的企业管理服务平台。它已支持IPD、精益、阿米巴等先进管理理念在3.1万余…

【MongoDB】集群搭建实战 | 副本集 Replica-Set | 分片集群 Shard-Cluster | 安全认证

文章目录 MongoDB 集群架构副本集主节点选举原则搭建副本集主节点从节点仲裁节点 连接节点添加副本从节点添加仲裁者节点删除节点 副本集读写操作副本集中的方法 分片集群分片集群架构目标第一个副本集第二个副本集配置集初始化副本集路由集添加分片开启分片集合分片删除分片 安…

[DC29 Quals] Reverse-Tiamat -wp

前言:我将尽量以自己做题时的思考过程来组织本文,所以本文可能不适合阅读,知识点也会比较散碎的出现。 ​1. qemu-user 简介 简单介绍一点本题所涉及的 qemu 相关知识,需要声明的是这一节不是对 qemu 的源码分析,仅仅…

【软件测试】Linux系统下搭建JDK+JMeter环境详细步骤,一篇概全...

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 Linux搭建JDK环境…

王道p18 07.将两个有序顺序表合并为一个新的有序顺序表,并由函数返回结果顺序表。(c语言代码实现)

视频讲解在这:👇 p18 第7题 c语言代码实现王道数据结构课后代码题_哔哩哔哩_bilibili 本题代码如下 int merge(struct sqlist* A, struct sqlist* B, struct sqlist* C) {if (A->length B->length > C->length)//大于顺序表的最大长度r…

NewStarCTF 2023 公开赛道 Web

NewStarCTF 2023 公开赛道 Web WEEK1|WEB 泄漏的秘密 泄露的秘密,直接看常见的目录robots.txt,www.zip直接那道两段flag 也可以用dirsearch工具扫描,但是BUUOJ平台的网站只能开底线程,不然全是429 PART ONE: flag{r0bots_1s_s0_us3ful $…

宝塔面板使用Supervisor进程守护插件,配置守护Mysql的操作教程。

本篇文章主要讲解,在宝塔面板中使用Supervisor进程守护插件,配置守护Mysql的操作教程。 作者:任聪聪 日期:2023年11月5日 一、安装守护进程插件 安装插件一、进程守护插件 安装说明:在软件商店中搜索“进程守护”&am…

Leetcode-1 两数之和

暴力穷举 class Solution {public int[] twoSum(int[] nums, int target) {int[] num new int[2];for(int i0;i<nums.length-1;i){for(int ji1;j<nums.length;j){if(nums[i]nums[j]target){num[0]i;num[1]j;}}}return num;} }HashMap&#xff0c;记录下标和对应值&…