【行为型模式】策略模式

一、策略模式概述

        策略模式(又叫政策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 ;@Overridepublic 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;@Overridepublic 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;@Overridepublic 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 {@Overridepublic void fly() {// TODO 自动生成的方法存根System.out.println("我在飞,用翅膀飞");}}
package Strategy.behavior;public class FlyNoWay implements FlyBehavior {
//不会飞@Overridepublic void fly() {// TODO 自动生成的方法存根}}
package Strategy.behavior;
//会叫
public class Quack implements QuackBehavior {@Overridepublic void quack() {// TODO 自动生成的方法存根System.out.println("我在呱呱叫");}}
package Strategy.behavior;
//不会叫
public class MuteQuack implements QuackBehavior {@Overridepublic void quack() {// TODO 自动生成的方法存根}
}
package Strategy.behavior;
//摩擦声
public class Squeak implements QuackBehavior {@Overridepublic 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();}@Overridepublic void display() {// TODO 自动生成的方法存根sSystem.out.println("我是一只诱饵鸭");}
}
package Strategy.behavior;
//绿头会飞鸭
public class MallardDuck extends Duck {public  MallardDuck() {quackBehavior=new Quack();flybehavior=new FlyWithWings();}@Overridepublic void display() {// TODO 自动生成的方法存根System.out.println("我是一只绿头,灰色羽毛的鸭子");}
}
package Strategy.behavior;
//红头会飞鸭
public class RedHeadDuck extends Duck {public RedHeadDuck() {quackBehavior=new Quack();flybehavior=new FlyWithWings();}@Overridepublic void display() {// TODO 自动生成的方法存根System.out.println("我是一只红头,灰色羽毛的鸭子");}
}
package Strategy.behavior;
//橡皮鸭
public class RubberDuck extends Duck {public RubberDuck(){quackBehavior=new Squeak();flybehavior =new FlyNoWay();}@Overridepublic 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.hqwc.cn/news/623700.html

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

相关文章

安装指定版本的ant-design-vue和指定版本的@ant-design/icons-vue 图标组件包

前言&#xff1a; 最近在完成公司的项目时&#xff0c;为了兼容其他的版本&#xff0c;需要安装指定版本的ant-design-vue和ant-design/icons-vue 图标组件包&#xff0c;安装成功之后&#xff0c;分享如下&#xff1a; 安装命令&#xff1a; ant-design-vue&#xff1a; 不…

HTML内联框架

前言&#xff1a; 我们有时候打开网页时会有广告窗的出现&#xff0c;而这些窗口并不是来自于本站的&#xff0c;而是来自于外部网页&#xff0c;只是被引用到了自己网页中而已。这一种技术可以通过内联来实现。 标签介绍&#xff1a; HTML 内联框架元素 (<iframe>) 表示…

自动化测试-如何优雅实现方法的依赖

在复杂的测试场景中&#xff0c;常常会存在用例依赖&#xff0c;以一个接口自动化平台为例&#xff0c;依赖关系&#xff1a; 创建用例 --> 创建模块 --> 创建项目 --> 登录。 用例依赖的问题 • 用例的依赖对于的执行顺序有严格的要求&#xff0c;比如让被依赖的方…

数据结构——栈(C++实现)

数据结构——栈 什么是栈栈的实现顺序栈的实现链栈的实现 今天我们来看一个新的数据结构——栈。 什么是栈 栈是一种基础且重要的数据结构&#xff0c;它在计算机科学和编程中扮演着核心角色。栈的名称源于现实生活中的概念&#xff0c;如一叠书或一摞盘子&#xff0c;新添加…

sort用法

前两个参数传范围&#xff0c;可以是迭代器也可以是指针&#xff0c;最后传比较方法。该方法判断cmp的第一个参数是否在第二个参数之前&#xff0c;比如这里想从小到大排序&#xff0c;x为小的时候在前&#xff0c;所以当x<y的时候我们返回1.

材料物理 笔记-6

原内容请参考哈尔滨工业大学何飞教授&#xff1a;https://www.bilibili.com/video/BV18b4y1Y7wd/?p12&spm_id_frompageDriver&vd_source61654d4a6e8d7941436149dd99026962 或《材料物理性能及其在材料研究中的应用》&#xff08;哈尔滨工业大学出版社&#xff09; 文…

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

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

前端开发框架BootStrap

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl BootStrap概述 Bootstrap是一个开源的前端框架&#xff0c;它由Twitter的设计师和开发者创建并维护。Bootstrap提供了许多现成的Web组件&#xff0c;可帮助开发者快速设计和…

免单优选电商模式:激发购买欲望的创新销售策略

免单优选电商模式&#xff0c;作为一种创新的销售策略&#xff0c;其核心在于通过价格优惠、渐进式激励和社交网络结合&#xff0c;有效刺激消费者的购买行为&#xff0c;进而推动销售业绩的快速增长。 一、合法合规&#xff0c;规避多层次奖励风险 该模式坚持合法合规的运营原…

【Web】VS Code 插件

专栏文章索引&#xff1a;Web 有问题可私聊&#xff1a;QQ&#xff1a;3375119339 目录 一、安装步骤 二、插件 1.Chinese (Simplified) (简体中文) 2.open in browser 3.vscode-icons 4.Live Server 5.Live Server Preview 6.翻译(英汉词典) 一、安装步骤 点击 “扩…

R-Tree的概念

R-Tree可以称作空间索引的基石&#xff0c;目前流行的时空索引架构都是基于R-Tree衍生而来。 R-Tree的概念 R-Tree 主要用于索引多维信息&#xff08;如地理点坐标、矩形或多边形&#xff09;的一种数据结构。R -Tree是由Guttman在1984年提出的&#xff0c;在理论和应用上都有…

软考-系统集成项目管理中级--进度管理(输入输出很重要!!!本章占分较高,着重复习)

本章历年考题分值统计(16年11月及以后按新教材考的&#xff09; 本章重点常考知识点汇总清单(学握部分可直接理解记忆) 12、参数估算:参数估算是一种基于历史数据和项目参数&#xff0c;使用某种算法来计算成本或持续时间的估算技术。参数估算是指利用历史数据之间的统计关系和…