设计模式-策略模式

一、定义

策略模式比较容易理解且很常见,主要思想就是将同一类型的算法封装为一个算法组,使得他们之间可以相互替换,此模式让算法变化独立于使用算法的客户。可能这样直接说比较抽象,下面的实现通过一个经典的鸭子类的例子来实现策略模式。

二、实现

面临的问题

首先有一个鸭子基类Duck,不同类型的鸭子都集成于这个基类,基类中有一些基本的方法:叫、游泳、飞,子类都会继承这些方法。

public abstract class Duck {public void swim(){System.out.println("游泳");}public void fly(){System.out.println("飞");}public void quack(){System.out.println("嘎嘎叫");}//每种鸭子外观不同,所以是抽象的public abstract void display();
}public class GaDuck extends Duck{@Overridepublic void display() {System.out.println("嘎嘎鸭的外观:黄头");}
}public class MallardDuck extends Duck {@Overridepublic void display() {System.out.println("绿头鸭的外观:绿头");}
}

这样没什么问题,但是如果新加了一个橡皮鸭类型呢,橡皮鸭既不会飞也不会叫,那应该怎么办?

这样也比较容易想到,重写父类的方法就好了嘛。

public class RubberDuck extends Duck{@Overridepublic void fly() {System.out.println("不会飞");}@Overridepublic void quack() {System.out.println("不会叫");}@Overridepublic void display() {System.out.println("这是一个橡皮鸭");}
}//测试:
public class DuckTest {public static void main(String[] args) {Duck rubberDuck = new RubberDuck();testDuck(rubberDuck);}public static void testDuck(Duck duck){duck.fly();duck.quack();duck.display();}
}//输出:
不会飞
不会叫
这是一个橡皮鸭

来了一个不会飞不会叫的橡皮鸭,我们可以重写父类的方法改进,但是如果后面又来了一种同样不会飞不会叫的木头鸭子呢?可能也是一样,重写方法,来多少个就重写多少个,但是这样是不是有悖于我们的设计原则?

  1. 首先,会出现大量的重复代码,都重写父类的方法改为不会飞不会叫;
  2. 然后这些行为都是重复的写死在类中,属于是直接面向实现编程而不是面向抽象编程;
  3. 最后,如果我们想修改某一类鸭子的行为,只能通过修改代码来实现,这是最不能接受的。

改进

既然飞和叫是每个鸭子都会有的行为,只不过不同类型的鸭子实现方法不同,且这些行为也不像鸭子的外观那样几乎每种鸭子都是独一无二的,比如飞的行为,只有两种,会飞和不会飞。

那我们就可以把这两种行为抽象为接口,具体的鸭子类可以自主选择这类行为下的实现。

首先,定义好行为的算法组,同时为了方便,我们直接把所有的行为都提前创建好实例放到工厂中。

飞行的行为:

public interface FlyBehavior {void fly();
}
public class FlyWithNoWay implements FlyBehavior{@Overridepublic void fly() {System.out.println("不能飞行");}
}
public class FlyWithWings implements FlyBehavior{@Overridepublic void fly() {System.out.println("使用翅膀飞行");}
}
public enum FlyEnum {NO_WAY("noWay","无法飞"),WING("wing","使用翅膀飞");//键名private final String key;//描述private final String desc;//...
}
public class FlyFactory {private static final Map<String,FlyBehavior> FLY_MAP = new HashMap<>();static{FLY_MAP.put(FlyEnum.NO_WAY.getKey(), new FlyWithNoWay());FLY_MAP.put(FlyEnum.WING.getKey(), new FlyWithWings());}public static FlyBehavior get(String flyKey){FlyBehavior flyBehavior = FLY_MAP.get(flyKey);if(flyBehavior == null){throw new RuntimeException("指定的飞行方式不存在");}return flyBehavior;}
}

叫的行为:

public interface QuackBehavior {void quack();
}
public class QuackWithGa implements QuackBehavior{@Overridepublic void quack() {System.out.println("嘎嘎叫");}
}
public class QuackWithGua implements QuackBehavior{@Overridepublic void quack() {System.out.println("Gua Gua 叫");}
}
public class QuackWithNoWay implements QuackBehavior{@Overridepublic void quack() {System.out.println("不会叫");}
}
public enum QuackEnum {GUAGUA("guagua", "呱呱叫"),GAGA("gaga", "嘎嘎叫"),NO_WAY("noWay", "不会叫");//键值private final String key;//描述private final String desc;//...
}
public class QuackFactory {private static final Map<String, QuackBehavior> QUACK_MAP = new HashMap<>();static{QUACK_MAP.put(QuackEnum.GUAGUA.getKey(), new QuackWithGua());QUACK_MAP.put(QuackEnum.GAGA.getKey(), new QuackWithGa());QUACK_MAP.put(QuackEnum.NO_WAY.getKey(), new QuackWithNoWay());}public static QuackBehavior get(String quackKey){QuackBehavior quackBehavior = QUACK_MAP.get(quackKey);if(quackBehavior == null){throw new RuntimeException("指定的叫声方式不存在");}return quackBehavior;}
}

然后修改鸭子的基类,把飞和叫的行为抽象为接口,交由子类从对应的算法组中选择

public abstract class Duck {//飞和叫会因为鸭子的不同而不同,所以使用策略模式,将他们抽离出来private FlyBehavior flyBehavior;private QuackBehavior quackBehavior;//抽象方法,说明public abstract void display();public void swim(){System.out.println("所有鸭子都会游泳");}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;}
}
//子类,嘎嘎鸭
public class GaDuck extends Duck {public GaDuck() {setFlyBehavior(FlyFactory.get(FlyEnum.WING.getKey()));setQuackBehavior(QuackFactory.get(QuackEnum.GAGA.getKey()));}@Overridepublic void display() {System.out.println("这是一个嘎鸭");}
}
//子类,橡皮鸭
public class RubberDuck extends Duck {public RubberDuck() {setFlyBehavior(FlyFactory.get(FlyEnum.NO_WAY.getKey()));setQuackBehavior(QuackFactory.get(QuackEnum.NO_WAY.getKey()));}@Overridepublic void display() {System.out.println("这是一只橡皮鸭");}
}

下面就可以测试了

public class DuckTest {public static void main(String[] args) {System.out.println("======================");testRubberDuck();System.out.println("======================");testGaDuck();}public static void testRubberDuck(){System.out.println("创造一个橡皮鸭,不会飞,不会叫");Duck rubberDuck = new RubberDuck();rubberDuck.display();rubberDuck.swim();rubberDuck.performFly();rubberDuck.performQuack();}public static void testGaDuck(){System.out.println("创造一个嘎嘎鸭,会飞,嘎嘎叫");Duck gagaDuck = new GaDuck();gagaDuck.display();gagaDuck.swim();gagaDuck.performFly();gagaDuck.performQuack();System.out.println("修改嘎嘎鸭,让他不会飞");gagaDuck.setFlyBehavior(FlyFactory.get(FlyEnum.NO_WAY.getKey()));gagaDuck.performFly();}
}//测试结果:
======================
创造一个橡皮鸭,不会飞,不会叫
这是一只橡皮鸭
所有鸭子都会游泳
不能飞行
不会叫
======================
创造一个嘎嘎鸭,会飞,嘎嘎叫
这是一个嘎鸭
所有鸭子都会游泳
使用翅膀飞行
嘎嘎叫
修改嘎嘎鸭,让他不会飞
不能飞行

至此,我们看到通过策略模式,实现很灵活的设置鸭子的飞和叫的行为,且支持改变这些行为而不用修改代码。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机图形学论文 | 面向制造的设计: 五轴铣削的几何制造可行性评估

&#x1f355;&#x1f355;&#x1f355;宝子们好久不见&#xff0c;新年快乐~~~&#xff0c;今天我们来更新一篇关于五轴CNC制造中的模型制造可达性分析的论文。老规矩&#xff1a; 红色是名词&#xff0c;蓝色是结论&#xff0c;绿色是文章工作&#xff0c;黄色是一些其他重…

deepseek搭建本地知识库

ollama是一个大模型的运行框架&#xff0c;在上面可以运行不同的大模型 部署deepseek 下载ollama&#xff1a;https://ollama.com/ 下载模型&#xff1a;https://ollama.com/library/deepseek-r1:1.5b ollama run deepseek-r1:1.5b运行起来之后&#xff0c;本地命令行就可以…

青少年编程与数学 02-009 Django 5 Web 编程 01课题、概要

青少年编程与数学 02-009 Django 5 Web 编程 01课题、概要 一、Django 5Django 5 的主要特性包括&#xff1a; 二、MVT模式三、官方网站四、内置功能数据库 ORM&#xff08;对象关系映射&#xff09;用户认证和授权表单处理模板引擎URL 路由缓存框架国际化和本地化安全性功能管…

deepseek本地部署-linux

1、官网推荐安装方法(使用脚本,我绕不过github,未采用) 登录ollama下载网站https://ollama.com/download/linux,linux下有下载脚本。 正常来说,在OS系统下直接执行脚本即可。 2、手动安装方法 2.1获取ollama-linux-arm64.tgz wget https://ollama.com/download/ollam…

多光谱技术在华为手机上的应用发展历史

2018 年&#xff0c;华为 P20 系列首次搭载 5 通道色温传感器&#xff0c;可帮助手机在不同光照条件下保持画面色彩一致性。 2020 年&#xff0c;华为 P40 系列搭载 8 通道多光谱色温传感器&#xff08;实际为 11 通道&#xff0c;当时只用 8 个通道检测可见光&#xff09;&am…

增加工作台菜单页面,AI问答应用支持上下文设置,数据库表索引优化,zyplayer-doc 2.4.8 发布啦!

zyplayer-doc是一款适合企业和个人使用的WIKI知识库管理工具&#xff0c;支持在线编辑富文本、Markdown、表格、Office文档、API接口、思维导图、Drawio以及任意的文本文件&#xff0c;专为私有化部署而设计&#xff0c;最大程度上保证企业或个人的数据安全&#xff0c;支持以内…

4.python+flask+SQLAlchemy+达梦数据库

前提 1.liunx Centos7上通过docker部署了达梦数据库。从达梦官网下载的docker镜像。(可以参考前面的博文) 2.windows上通过下载x86,win64位的达梦数据库,只安装客户端,不安装服务端。从达梦官网下载达梦数据库windows版。(可以参考前面的博文) 这样就可以用windows的达…

基础入门-网站协议身份鉴权OAuth2安全Token令牌JWT值Authirization标头

知识点&#xff1a; 1、网站协议-http/https安全差异&#xff08;抓包&#xff09; 2、身份鉴权-HTTP头&OAuth2&JWT&Token 一、演示案例-网站协议-http&https-安全测试差异性 1、加密方式 HTTP&#xff1a;使用明文传输&#xff0c;数据在传输过程中可以被…

【零基础学Mysql】常用函数讲解,提升数据操作效率的利器

以耳倾听世间繁华&#xff0c;以语表达心中所想 大家好,我是whisperrrr. 前言&#xff1a; 大家好&#xff0c;我是你们的朋友whisrrr。在日常工作中&#xff0c;MySQL作为一款广泛使用的开源关系型数据库&#xff0c;其强大的功能为我们提供了便捷的数据存储和管理手段。而在…

C++ 使用CURL开源库实现Http/Https的get/post请求进行字串和文件传输

CURL开源库介绍 CURL 是一个功能强大的开源库&#xff0c;用于在各种平台上进行网络数据传输。它支持众多的网络协议&#xff0c;像 HTTP、HTTPS、FTP、SMTP 等&#xff0c;能让开发者方便地在程序里实现与远程服务器的通信。 CURL 可以在 Windows、Linux、macOS 等多种操作系…

win编译openssl

一、perl执行脚本 1、安装perl脚本 perl安装 2、配置perl脚本 perl Configure VC-WIN32 no-asm no-shared --prefixE:\openssl-x.x.x\install二、编译openssl 1、使用vs工具编译nmake 如果使用命令行nmake编译会提示“无法打开包括文件: “limits.h”“ 等错误信息 所以…

idea启动报错# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffccf76e433

# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc0x00007ffccf76e433, pid17288, tid6696 # # JRE version: (11.0.248) (build ) # Java VM: OpenJDK 64-Bit Server VM (11.0.248-LTS, mixed mode, sharing, tiered, compressed oops, g1 gc, windows-amd64) 不知道为什么…

穷举vs暴搜vs深搜vs回溯vs剪枝系列一>不同路径 III

目录 整体思路&#xff1a;代码设计&#xff1a;代码呈现&#xff1a; 整体思路&#xff1a; 代码设计&#xff1a; 代码呈现&#xff1a; class Solution {int ret,step;int m,n;boolean[][] vis;public int uniquePathsIII(int[][] grid) {m grid.length;n grid[0].length…

Idea 2024.3 使用CodeGPT插件整合Deepseek

哈喽&#xff0c;大家好&#xff0c;我是浮云&#xff0c;最近国产大模型Deepseek异常火爆&#xff0c;作为程序员我也试着玩了一下&#xff0c;首先作为简单的使用&#xff0c;大家进入官网&#xff0c;点击开始对话即可进行简单的聊天使用&#xff0c;点击获取手机app即可安装…

Houdini subuv制作输出阵列图

在游戏开发中经常需要用到sheet阵列图&#xff0c;并用其制作翻页动画。通过Houdini强大的节点组合可以配合输出subuv阵列图供游戏引擎使用。 本文出处&#xff1a;https://zhuanlan.zhihu.com/p/391796978 博主参考学习并写该文。 1.在obj分类下创建font节点以进行测试&#…

使用page assist浏览器插件结合deepseek-r1 7b本地模型

为本地部署的DeepSeek R1 7b模型安装Page Assist&#xff0c;可以按照以下步骤进行&#xff1a; 一、下载并安装Ollama‌ 首先&#xff0c;你需要下载并安装Ollama&#xff0c;这是部署DeepSeek所必需的工具。你可以访问Ollama的官方网站&#xff08;ollama.com&#xff09;下…

oracle: 事务,视图

事务 事务是数据库的最小逻辑单元&#xff0c;就是数据库中的一个最小的操作单位。 事务是由多条SQL语句组成的一个集合&#xff0c;有事务统一控制这些SQL语句的执行。 事务的属性 被简称为ACID属性, 是4个属性单词的首字母 脏读,幻读,不可重复读 是三种常见的并发问题&…

Unity3D引擎首次用于光伏仿真设计软件爆火

在光伏设计领域&#xff0c;绿虫光伏仿真设计软件宛如一匹黑马&#xff0c;凭借其基于 Unity3D 引擎的强大功能&#xff0c;为行业带来了全新的解决方案。借助 Unity3D 引擎技术&#xff0c;实现了游戏级高清画面&#xff0c;2D/3D 自由转换&#xff0c;让场景代入感极强&#…

寒假2.6--SQL注入之布尔盲注

知识点 原理&#xff1a;通过发送不同的SQL查询来观察应用程序的响应&#xff0c;进而判断查询的真假&#xff0c;并逐步推断出有用的信息 适用情况&#xff1a;一个界面存在注入&#xff0c;但是没有显示位&#xff0c;没有SQL语句执行错误信息&#xff0c;通常用于在无法直接…

有用的sql链接

『SQL』常考面试题&#xff08;2——窗口函数&#xff09;_sql的窗口函数面试题-CSDN博客 史上最强sql计算用户次日留存率详解&#xff08;通用版&#xff09;及相关常用函数 -2020.06.10 - 知乎 (zhihu.com) 1280. 学生们参加各科测试的次数 - 力扣&#xff08;LeetCode&…