【行为型模式】策略模式

一、策略模式概述

        策略模式(又叫政策Policy模式),属于对象行为模式下的:Strategy类提供了可插入式(Pluggable)算法的实现方案。

        策略模式的定义-意图:定义一系列算法,将每一个算法封装起来,并让它们互相替换。策略模式让算法可以独立于使用它的客户变化。

        模式策略的优缺点

  • 优点
    • 1.提供了对开闭(开时针对扩展功能是开放的,闭对修改功能是关闭的)原则的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为;
    • 2.提供了管理相关的算法族的办法;
    • 3.提供了一种可以替换继承关系的办法;
    • 4.可以避免多重条件选择语句;
    • 5.提供了一种算法的复用机制,不同环境类可以方便地复用策略类。(单一职责)       
  • 缺点
    • 1.客户端必须知道所有的策略类,并自行决定使用哪一个策略类;
    • 2.将造成系统产生很多具体策略类;
    • 3.无法同时在客户端使用多个策略类。
  • 适用环境
    • 1.一种系统需要动态地在几种算法中选择一种;
    • 2.避免使用难以维护的多重条件选择语句;
    • 3.不希望客户端知道复杂的、与算法相关的数据结构,提高算法的保密性与安全。

二、代码实现

        策略模式的结构,包含3个角色:

  • 1.环境(Context)角色:持有一个Strategy类的引用;
  • 2.抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需要的接口;
  • 3.具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。
2.1 售票策略
        2.1.1 抽象策略角色(接口实现,接口名为Discount)
package Strategy.Mticket;
//抽象策略,打折
public interface Discount {
	public double calculate(double price);
}
        2.1.2 具体策略角色:儿童票(ChildrenDiscount)、学生票(StudentDiscount)、VIP票(VIPDiscount)
package Strategy.Mticket;
//具体策略,儿童票
public class ChildrenDiscount implements Discount {
	//代码的可维护性使用全局变量
	private final double DISCOUNT = 10 ;
	@Override
	public double calculate(double price) {
		// TODO 自动生成的方法存根
		if(price>=20) {
		System.out.println("儿童票:");
		return price - DISCOUNT;
		}
		else {
			return price;
		}		
	}
}
package Strategy.Mticket;
//具体策略,学生票
public class StudentDiscount implements Discount {
	private final double DISCOUNT=0.8;
	@Override
	public double calculate(double price) {
		// TODO 自动生成的方法存根
		System.out.println("学生票:");
		return price * DISCOUNT;
	}
}
package Strategy.Mticket;
//具体策略,VIP票
public class VIPDiscount implements Discount {
	private final double DISCOUNT=0.5;
	@Override
	public double calculate(double price) {
		// TODO 自动生成的方法存根
		System.out.println("VIP票:");
		System.out.println("增加积分:");
		return price * DISCOUNT;
	}
}
        2.1.3 环境角色:电影票(MovieTicket)
package Strategy.Mticket;
//环境类,电影票
public class MovieTicket {
	private double price;
	private Discount discount; //对抽象折扣类的引用
	
	/*public double getPrice() {
		//调用折扣类的折扣价计算方法
		//rerurn折后价
		return discount.calculate(this.price);
	}*/
	public double getPrice() {
		return price;
	}
	public double getDiscountPrice() {
		return discount.calculate(this.price);
	}
	
	public void setPrice(double price) {
		this.price = price;
	}
	
	public Discount getDiscount() {
		return discount;
	}
	//注入一个折扣类
	public void setDiscount(Discount discount) {
		this.discount = discount;
	}
	
}
        2.1.4 main方法调用实现策略模式
package Strategy.Mticket;

public class Client2 {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		MovieTicket mt =new MovieTicket();
		mt.setPrice(60.0);
		//mt.setDiscount(new VIPDiscount());
		//Discount ds =new StudentDiscount();
		Discount ds =new VIPDiscount();
		mt.setDiscount(ds);
		System.out.println("折后价为:"+mt.getDiscountPrice());
		
	}

}
        2.1.5 实例化工具代码(XMLUtil)

        如果想利用配置文件来实例化对象,可以减轻对代码的更改,直接对配置文件修改就可以。具体代码如下:

package Strategy.Mticket;

import java.io.*;
import javax.xml.parsers.*;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.*;
//实例化对象,配置文件就是想要s实例的对象
public class XMLUtil {
	//该方法用于从XML配置文件中提取具体类类名,并返回一个实例对象
	public static Object getBean() {
		try {
		//创建DOM文档对象
		DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = dFactory.newDocumentBuilder();
		Document doc;
		//file里就是配置文件
		doc =builder.parse(new File("src//Strategy//Mticket//config2.xml"));
		
		//获取包含类名的文本节点
		NodeList nl =doc.getElementsByTagName("className");
		//item这是一个数组,就是调用xml文件中的className内容
		Node classNode=nl.item(0).getFirstChild();
		//cName为类名,getNodeValue为字符串类型方法
		String cName = classNode.getNodeValue();
		
		//通过类名生成实例对象并将其返回
		//forName为java的反射技术
		Class c = Class.forName(cName);
		Object obj = c.newInstance();
		return obj;
		}catch(Exception e) {
			e.printStackTrace();
			return null;
		}
		
	}
}
        2.1.6 XML配置文件(config.xml)
<?xml version="1.0" encoding="UTF-8"?>
<config>
<className>Strategy.Mticket.VIPDiscount</className>
</config>
        2.1.7 利用配置文件的main方法实现
package Strategy.Mticket;

public class Client {
	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		MovieTicket mt = new MovieTicket();
		double originalPrice = 60.0;
		double currentPrice;
		
		mt.setPrice(originalPrice);
		System.out.println("原始价格为:"+originalPrice);
		System.out.println("-----------------------------");
		
		Discount discount;
		//读取配置文件并反射生成具体折扣对象
		//强转
		discount =(Discount)XMLUtil.getBean();
		mt.setDiscount(discount);//注入折扣对象
		
		currentPrice = mt.getDiscountPrice();
		System.out.println("折后价为:"+currentPrice);
	}

}
        2.1.8 UML图 

2.2 鸭子行为策略

进阶版策略模式

甲方:我需要一堆鸭子,红色的,绿色的,黑色的,还要会飞!还要会叫!

乙方:明白,N种鸭子就像电影票一样,只要继承了我的Duck类然后重写,就搞定一切!

甲方:哦吼!为什么橡皮鸭子会在天上飞?

乙方:无脑继承类是不对的!!!

解决方案:只用封装,继承好像不行,好像还有一个多态(接口)?是不是可以把飞这个行为定义成接口,然后把这个接口, 放到鸭子基类里面去!

真正的策略模式核心即:封装行为,依赖接口,组合代替继承!

        2.2.1 抽象策略角色(鸭子抽象基类Duck、飞行为接口FlyBehavior、叫行为接口QuackBehavior)
package Strategy.behavior;
//抽象策略,鸭子
public abstract class Duck {
	/**
     * 飞行行为是动态的,可能会变的,因此抽成多个接口的组合,而不是让Duck类继承
     */
	//接口变量
	FlyBehavior flybehavior;//面向接口编程
	QuackBehavior quackBehavior;
	
	public void createfly() {
		flybehavior.fly();
	}
	/**
     * 每个鸭子的叫声不同,抽象成接口
     */
	public void createquack() {
		quackBehavior.quack();
	}
	//为了测试方便
	public void test() {
		this.display();
		this.createquack();
		this.createfly();
		this.swim();
	}
	public void swim() {
		System.out.println("我在游泳");
	}
	public abstract void display();
}
package Strategy.behavior;
// 飞行为
public interface FlyBehavior {
	public void fly();
}
package Strategy.behavior;
//叫行为
public interface QuackBehavior {
	public void quack();
}
        2.2.2 具体策略角色(用翅膀飞FlyWithWings、不会飞FlyNoWay、会叫Quack、不会叫MuteQuack、摩擦声Squeak)
package Strategy.behavior;
//会飞
public class FlyWithWings implements FlyBehavior {

	@Override
	public void fly() {
		// TODO 自动生成的方法存根
		System.out.println("我在飞,用翅膀飞");
	}

}
package Strategy.behavior;

public class FlyNoWay implements FlyBehavior {
//不会飞
	@Override
	public void fly() {
		// TODO 自动生成的方法存根
	}

}
package Strategy.behavior;
//会叫
public class Quack implements QuackBehavior {

	@Override
	public void quack() {
		// TODO 自动生成的方法存根
		System.out.println("我在呱呱叫");
	}

}
package Strategy.behavior;
//不会叫
public class MuteQuack implements QuackBehavior {

	@Override
	public void quack() {
		// TODO 自动生成的方法存根

	}
}
package Strategy.behavior;
//摩擦声
public class Squeak implements QuackBehavior {

	@Override
	public void quack() {
		// TODO 自动生成的方法存根
		System.out.println("我不会呱呱叫,但是我能发出橡皮与空气的摩擦声");
	}

}
        2.2.3 环境角色(诱饵鸭DecoyDuck、绿头会飞鸭MallardDuck、红头会飞鸭RedHeadDuck、橡皮鸭RubberDuck)
package Strategy.behavior;
//诱饵鸭
public class DecoyDuck extends Duck{
	public DecoyDuck() {
		quackBehavior =new MuteQuack();
		flybehavior =new FlyNoWay();
		
	}
	@Override
	public void display() {
		// TODO 自动生成的方法存根s
		System.out.println("我是一只诱饵鸭");
	}
}
package Strategy.behavior;
//绿头会飞鸭
public class MallardDuck extends Duck {
	public  MallardDuck() {
		quackBehavior=new Quack();
		flybehavior=new FlyWithWings();
	}
	@Override
	public void display() {
		// TODO 自动生成的方法存根
		System.out.println("我是一只绿头,灰色羽毛的鸭子");
	}
}
package Strategy.behavior;
//红头会飞鸭
public class RedHeadDuck extends Duck {
	
	public RedHeadDuck() {
		quackBehavior=new Quack();
		flybehavior=new FlyWithWings();
	}
	@Override
	public void display() {
		// TODO 自动生成的方法存根
		System.out.println("我是一只红头,灰色羽毛的鸭子");
	}
}
package Strategy.behavior;
//橡皮鸭
public class RubberDuck extends Duck {
	
	public RubberDuck(){
		quackBehavior=new Squeak();
		flybehavior =new FlyNoWay();
	}
	@Override
	public void display() {
		// TODO 自动生成的方法存根
		System.out.println("我是一只黄色的橡皮鸭");
	}
}
        2.2.4 main方法调用实现策略模式
package Strategy.behavior;

public class Test {
	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		Duck ducks[]=new Duck[4];
		ducks[0]=new MallardDuck();
		ducks[1]=new RedHeadDuck();
		ducks[2]=new RubberDuck();
		ducks[3]=new DecoyDuck();
		ducks[0].test();
		ducks[1].test();
		ducks[2].test();
		ducks[3].test();			
	}
}
        2.2.5 UML图

三、代码结构

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

.NET MVC API Swagger 自动生成API文档入坑

开发环境 Win10 VS2022 .NET8.0 1.从NuGet添加Swagger 在解决方案资源管理器中右键单击项目>管理 NuGet 包 将包源设置为“nuget.org” 确保启用“包括预发行”选项 在搜索框中输入“Swashbuckle.AspNetCore” 从“浏览”选项卡中选择最新的“Swashbuckle.AspNetCore”包&a…

OCCT几何内核开发-TopoDS_Shape

如果要基于OCCT几何内核搞建模算法&#xff0c;特别是想开发自己的算法&#xff0c;需要深刻理解拓扑与几何的关系、相关的数据结构&#xff0c;TopoDS_Shape、TopoDS_TShape、BRep_TFace、Tolerances等。 一个简单Box的数据结构 两个面缝合&#xff08;Sewing&#xff09;后的…

优惠券布局的最终方案------css属性mask

先贴图&#xff1a; 以上这些都是通过mask去实现出来&#xff1a; <!DOCTYPE html><html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"&g…

【多模态检索】Coarse-to-Fine Visual Representation

快手文本视频多模态检索论文 论文&#xff1a;Towards Efficient and Effective Text-to-Video Retrieval with Coarse-to-Fine Visual Representation Learning 链接&#xff1a;https://arxiv.org/abs/2401.00701 摘要 近些年&#xff0c;基于CLIP的text-to-video检索方法…

FreeRTOS_day1

1.总结keil5下载代码和编译代码需要注意的事项 下载代码前要对仿真进行设置 勾选后代码会立刻执行 勾选后会导致代码不能执行 写代码的时候要写在对应的begin和end之间&#xff0c;否则会被覆盖 2.总结STM32Cubemx的使用方法和需要注意的事项 ①打开软件&#xff0c;新建工程…

初学python记录:力扣924. 尽量减少恶意软件的传播

题目&#xff1a; 给出了一个由 n 个节点组成的网络&#xff0c;用 n n 个邻接矩阵图 graph 表示。在节点网络中&#xff0c;当 graph[i][j] 1 时&#xff0c;表示节点 i 能够直接连接到另一个节点 j。 一些节点 initial 最初被恶意软件感染。只要两个节点直接连接&#x…

BK9535可替代BK9531 BEKEN博通 无线高品质语音发射传输芯片 提供开发资料

概 述 BK9531已经停产&#xff0c;厂家推出升级替代芯片BK9535 BK9535芯片是用于无线高品质语音发射传输的芯片&#xff0c;芯片覆盖频段范围为&#xff1a;V段&#xff08;160~270MHz&#xff09;、U段&#xff08;450~980MHz&#xff09;、1G频段&#xff08;980~1176MHz&a…

一款可自动跳广告的安卓App开源项目

开放权限有风险&#xff0c;使用App需谨慎&#xff01; gkd 基于 无障碍 高级选择器 订阅规则 的自定义屏幕点击 APP 功能 基于 高级选择器 订阅规则 快照审查, 它可以实现 点击跳过任意开屏广告/点击关闭应用内部任意弹窗广告, 如关闭百度贴吧帖子广告卡片/知乎回答底…

HarmonyOS开发案例:【智能煤气检测】

样例简介 智能煤气检测系统通过实时监测环境中烟雾浓度&#xff0c;当一氧化碳浓度超标时&#xff0c;及时向用户发出警报。在连接网络后&#xff0c;配合数字管家应用&#xff0c;用户可以远程配置智能煤气检测系统的报警阈值&#xff0c;远程接收智能煤气检测系统报警信息。…

华为再次布局新行业:合作伙伴已超前谋划,该领域将大有可为

华为布局新行业 华为向外界公布了一个重要信息&#xff1a;在过去的三年里&#xff0c;尽管受到美国的制裁&#xff0c;华为仍然成功地完成了超过13000个元器件的国产替代研发&#xff0c;以及4000多块电路板的迭代开发。 不仅在硬件领域取得了显著成就&#xff0c;在软件和生…

AutoMQ 登顶 Hacker News: 开源项目流量的第一桶金以及经验分享

01 事件回顾 2024 年 4 月 8 日中午&#xff0c;随着 AutoMQ 的一则简短的标题内容&#xff1a;Show HN: AutoMQ - A Cost-Effective Kafka Distro That Can Autoscale in Seconds[1] 成功登顶 Hacker News &#xff08;HN&#xff09; &#xff0c;我们迎来了大量优质、精准的…

为什么一开始不被看好的单片机,现在概括了所有数据产品行业?

这主要归因于技术和认知的局限。 在其发展初期&#xff0c;单片机的性能、存储容量以及开发工具都颇为有限&#xff0c;难以契合复杂应用的种种需求。彼时&#xff0c;许多人确实难以洞察到它的未来走向。 然而&#xff0c;时过境迁&#xff0c;人们逐步领悟到了单片机在各个…

密码学 | 椭圆曲线数字签名方法 ECDSA(下)

目录 10 ECDSA 算法 11 创建签名 12 验证签名 13 ECDSA 的安全性 14 随机 k 值的重要性 15 结语 ⚠️ 原文&#xff1a;Understanding How ECDSA Protects Your Data. ⚠️ 写在前面&#xff1a;本文属于搬运博客&#xff0c;自己留着学习。同时&#xff0c;经过几…

部署Zabbix代理服务器

目录 1.准备环境 2.设置 zabbix 的下载源 3.安装 zabbix 所需的数据库 3.1添加数据库用户&#xff0c;以及 zabbix 所需的数据库信息 3.2导入数据库信息 4.修改 zabbix-proxy 配置文件 5.启动 zabbix-proxy 6.在所有主机上配置 hosts 解析 7.在 Web 页面配置 agent 代…

市面上加密混淆软件的比较和推荐

引言 市面上有许多加密混淆软件可供开发者使用&#xff0c;但哪些软件是最好用的&#xff1f;哪些软件受到开发者的喜爱&#xff1f;本文将根据一次在CSDN上的投票结果&#xff0c;为大家介绍几款在程序员中普及度较高的加密软件。以下是投票结果&#xff0c;希望能对大家的选择…

什么是组网?如何远程组网?

在当今数字化时代&#xff0c;组网已成为企业提高工作效率、节省时间和成本的关键技术。组网是将多台计算机或其他网络设备连接起来&#xff0c;形成一个互联互通的网络系统。本文将概述组网的主要目的、实现方式及其价值&#xff0c;并深入分析远程组网策略。 1. 组网目的与价…

BK9531 BK9532上海博通BEKEN 提供开发资料

.概述 BK9531/BK9532 芯片是用于无线高品质语音传输的芯片组&#xff0c;包括发射芯片BK9531 和接收芯片 BK9532&#xff0c;每个芯片覆盖频段范围为&#xff1a;V 段160~270MHz 和 U 段500~980MHz。 BK9531/BK9532 采用数字调制和高性能音频 ADC 和 DAC&#xff0c;配合极低延…

idea2023专业版安装破解+maven配置教程

前言 上一篇文章已经介绍了maven在Win10系统的安装配置教程。基于Win10的maven配置环境&#xff0c;本篇文章将介绍idea2023的安装破解教程及maven在idea2023的配置教程&#xff08;同时会将maven在idea2023的配置教程内容补充至上一篇文章&#xff09;。 一、idea2023下载安…

再也不想用丑东西了!一个高颜值的备忘录,分享给你们【文末领源码】

谁工作中不得有点丢三落四的&#xff0c;但是被老大点名批评确实有点过不去了&#xff0c;提醒小伙伴们把必要的事情挂出来&#xff0c;同事说虽然已经有一款系统&#xff0c;但展示的不好看&#xff0c;根本不想用&#xff0c;于是找到了一款颜值还不错的备忘录工具 -- memo …

工作的第五天了

1.今天内容 1.现在的基本都增删改查都有 2.下一步做规格商品添加规格的方式 3.商品规格比较特殊 4.我们添加一个商品。通用一个商品&#xff0c;然后下面添加规格信息 5.如何做 6.第一个是添加商品 7.商品对应多个属性方式&#xff0c;简单来说是一个一对多的方式&#x…
最新文章