【设计模式学习笔记】 之 策略模式

简介:

经常网购的可能发现京东、淘宝等电商平台每到什么节日都会进行打折,这种打折就是一种策略,策略模式的意思呢,就是把不变的和易变的策略分离开,需要什么策略时候,把需要的策略传给执行体,而不是执行体内置这些策略。

举例1:

我们有一个CD播放器,cd播放器中如果内置了一些歌曲的话,那么我们只能听这些歌曲。但是cd本身并没有内置播放资源(播放策略),而是通过插入cd进行播放cd碟片中的资源信息。

有了这个思路,我们先创建一个CD接口,让每个CD实现类实现CD接口,cd接口中有一个sing方法

 1 package com.mi.statege.statege1;
 2
 3 /**
 4  * CD接口
 5  * @author hellxz
 6  */
 7 public interface CD {
 8
 9     //cd的播放方法,为了不与CDPlayer方法重名,使用sing
10     public void sing();
11
12 }
 1 package com.mi.statege.statege1;
 2
 3 /**
 4  * 周杰伦的专辑
 5  * @author hellxz
 6  */
 7 public class JayCD implements CD {
 8
 9     @Override
10     public void sing() {
11         System.out.println("稻香");
12         System.out.println("听妈妈的话");
13         System.out.println("最长的电影");
14         System.out.println("等你下课");
15         System.out.println("红尘客栈");
16         System.out.println("发如雪");
17     }
18
19 }
 1 package com.mi.statege.statege1;
 2
 3 /**
 4  * 五月天的专辑
 5  * @author hellxz
 6  */
 7 public class WuyuetianCD implements CD {
 8
 9     @Override
10     public void sing() {
11         System.out.println("倔强");
12         System.out.println("你不是真正的快乐");
13     }
14
15 }

接下来 创建一个CDPlayer 播放器类,这个类中持有CD接口引用,通过set方法为cd赋值,在play方法中调用cd的sing方法播放唱片内容

 1 package com.mi.statege.statege1;
 2
 3 /**
 4  * CD播放器
 5  * @author hellxz
 6  */
 7 public class CDPlayer {
 8
 9     private String brand; //CD播放器的品牌
10
11     private CD cd; //持有cd的引用
12
13     public CDPlayer(String brand) { //构造方法初始化品牌
14         this.brand = brand;
15     }
16
17     //播放
18     public void play() {
19         System.out.println(brand+"牌CD播放器启动了……");
20         cd.sing();
21     }
22
23     //getters & setters
24     public CD getCd() {
25         return cd;
26     }
27
28     public void setCd(CD cd) {
29         this.cd = cd;
30     }
31
32 }

测试类

 1 package com.mi.statege.statege1;
 2
 3 public class Test {
 4
 5     public static void main(String[] args) {
 6         CDPlayer player = new CDPlayer("步步高");
 7         player.setCd(new WuyuetianCD());
 8 //        player.setCd(new JayCD());
 9         player.play();
10     }
11 }

输出:

步步高牌CD播放器启动了……
倔强
你不是真正的快乐

打开第8行,关掉第七行

步步高牌CD播放器启动了……
稻香
听妈妈的话
最长的电影
等你下课
红尘客栈
发如雪

观察输出,播放器中播放的歌曲的确切换了

举例2:

这个是柳大对于hibernate组合查询语句做的一个通用方法,使用了策略模式,试想:如果我们不用策略模式,而是通过传参的判断,通过传的参数进行拼接sql的话,它同时需要反射生成POJO类,这样一来POJO类名必须要和表名相同,而且如果我们需要传入的参数是like查询而不是=的时候,这样会更加麻烦,对客户端程序员的限制更大。

下面开始实现一下柳大的CommonQuery中如何使用的策略模式吧!

首先创建一个实体POJO的接口,并实现该接口,实现类为Student

 1 package com.mi.statege.statege2;
 2
 3 /**
 4  * 定义实体POJO接口
 5  * @author hellxz
 6  */
 7 public interface Entity {
 8
 9     //获取sql的方法,返回一个拼接好的query sql
10     public String getSql();
11 }

Student类中有两个参数,学号以及姓名,学号使用“=”查询,姓名使用“like %str%”进行模糊查询,不为空则将不为空的参数拼接进sql

 1 package com.mi.statege.statege2;
 2
 3 /**
 4  * 学生POJO
 5  * @author hellxz
 6  */
 7 public class Student implements Entity {
 8
 9     private int stuNo; //学号
10     private String stuName; //姓名
11
12     @Override
13     public String getSql() { //重写获取query sql方法
14         StringBuffer sb = new StringBuffer();
15         sb.append("select * from student where 1=1 ");
16         if(stuNo != 0) {//非空则学号使用"="进行查询
17             sb.append(" and stuNo = "+stuNo+" ");
18         }
19         if(stuName != null && !stuName.trim().equals("")) {//非空则学生姓名使用"like %str%"进行查询
20             sb.append(" and stuName like ‘%"+stuName+"%‘; ");
21         }
22         return sb.toString();
23     }
24
25     //getters & setters
26     public int getStuNo() {
27         return stuNo;
28     }
29
30     public void setStuNo(int stuNo) {
31         this.stuNo = stuNo;
32     }
33
34     public String getStuName() {
35         return stuName;
36     }
37
38     public void setStuName(String stuName) {
39         this.stuName = stuName;
40     }
41
42 }

通用查询类CommonQuery,运用多态动态指定POJO类型,获取对应的sql

 1 package com.mi.statege.statege2;
 2
 3 /**
 4  * 通用查询类
 5  * @author hellxz
 6  */
 7 public class CommonQuery {
 8
 9     private Entity entity; //持有一个Entity接口的引用
10
11     //查询方法
12     public void query() {
13         //调用entity引用,运行期间绑定到实际类型中,调用getSql方法获取拼接好的sql语句
14         String sql = entity.getSql();
15         System.out.println(sql); //打印sql语句
16     }
17
18     //getters & setters
19     public Entity getEntity() {
20         return entity;
21     }
22
23     public void setEntity(Entity entity) {
24         this.entity = entity;
25     }
26
27 }

测试类

 1 package com.mi.statege.statege2;
 2
 3 public class Test {
 4
 5     public static void main(String[] args) {
 6         Student student = new Student();
 7         student.setStuNo(1);
 8         student.setStuName("Hellxz");
 9         CommonQuery query = new CommonQuery();
10         query.setEntity(student);
11         query.query();
12     }
13 }

查看输出

select * from student where 1=1  and stuNo = 1  and stuName like ‘%Hellxz%‘; 

这样一来,我们就可以通过实现Entity接口的对象让CommonQuery对象set进去就可以返回正确的sql了,而且不会有之前那些烦人的问题了

总结:

将执行体与策略分离开,这样执行体中无需内置策略,只需要在执行特定策略的时候将策略set到执行体中执行策略内容即可

优点: 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。

缺点: 1、策略类会增多。 2、所有策略类都需要对外暴露。

使用场景: 1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。

      2、一个系统需要动态地在几种算法中选择一种。

      3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。

注意事项:如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。

原文地址:https://www.cnblogs.com/hellxz/p/8449964.html

时间: 2024-10-12 11:48:07

【设计模式学习笔记】 之 策略模式的相关文章

设计模式学习笔记之策略模式

策略模式 定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户. 说明: 1.可以动态地改变对象的行为: 2.各个策略算法的平等性,各个策略算法在实现上是相互独立的,相互之间没有任何依赖的(由此,策略模式也可以描述为“策略算法是相同行为的不同实现”): 3.在运行期间,策略模式在某一时刻,只能使用一个具体的策略算法实现对象,虽然可以动态改变对象行为,但同时只能使用一个: 4.策略模式可以很简单的扩展新的实现算法.方法:先写一个策略算法来实现新的需求,然后在客

Java 设计模式学习笔记1——策略模式(Duck例子)

0.假设现有工程(Duck)中遇到为类添加功能的问题,如何设计类添加新的功能? 1.利用继承提供的Duck(鸭子)的行为会导致哪些缺点? (1)代码在多个子类中重复 (2)很多男知道所有鸭子的全部行为 (3)运行时的行为不容易改变 (4)改变会牵一发动全身,造成其他鸭子的不想要的改变 [设计原则] 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需呀变化的代码混在一起 2.分开变化与不会变化的部分 将Duck分成两部分,鸭子类和鸭子行为. 类的固有属性和共用的方法写在类中,行为另起一个类

大话设计模式读书笔记2——策略模式

策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类直接的耦合. UML 图: 根据<大话设计模式>——第二章 商场促销这个案例代码来简单的记录一下策略模式的使用方式: /// <summary> /// 现金收费抽象类 /// </summary> public abstract class CashSuper { /// <summary> ///

设计模式学习笔记--状态(State)模式

写在模式学习之前 什么是设计模式:在我们进行程序设计时,逐渐形成了一些典型问题和问题的解决方案,这就是软件模式:每一个模式描述了一个在我们程序设计中经常发生的问题,以及该问题的解决方案:当我们碰到模式所描述的问题,就可以直接用相应的解决方法去解决这个问题,这就是设计模式. 设计模式就是抽象出来的东西,它不是学出来的,是用出来的:或许你根本不知道任何模式,不考虑任何模式,却写着最优秀的代码,即使以"模式专家"的角度来看,都是最佳的设计,不得不说是"最佳的模式实践",这

设计模式学习笔记--备忘录(Mamento)模式

写在模式学习之前 什么是设计模式:在我们进行程序设计时,逐渐形成了一些典型问题和问题的解决方案,这就是软件模式:每一个模式描述了一个在我们程序设计中经常发生的问题,以及该问题的解决方案:当我们碰到模式所描述的问题,就可以直接用相应的解决方法去解决这个问题,这就是设计模式. 设计模式就是抽象出来的东西,它不是学出来的,是用出来的:或许你根本不知道任何模式,不考虑任何模式,却写着最优秀的代码,即使以"模式专家"的角度来看,都是最佳的设计,不得不说是"最佳的模式实践",这

设计模式学习笔记--迭代(Iterator)模式

写在模式学习之前 什么是设计模式:在我们进行程序设计时,逐渐形成了一些典型问题和问题的解决方案,这就是软件模式:每一个模式描述了一个在我们程序设计中经常发生的问题,以及该问题的解决方案:当我们碰到模式所描述的问题,就可以直接用相应的解决方法去解决这个问题,这就是设计模式. 设计模式就是抽象出来的东西,它不是学出来的,是用出来的:或许你根本不知道任何模式,不考虑任何模式,却写着最优秀的代码,即使以"模式专家"的角度来看,都是最佳的设计,不得不说是"最佳的模式实践",这

设计模式学习笔记--访问者(Visitor)模式

写在模式学习之前 什么是设计模式:在我们进行程序设计时,逐渐形成了一些典型问题和问题的解决方案,这就是软件模式:每一个模式描述了一个在我们程序设计中经常发生的问题,以及该问题的解决方案:当我们碰到模式所描述的问题,就可以直接用相应的解决方法去解决这个问题,这就是设计模式. 设计模式就是抽象出来的东西,它不是学出来的,是用出来的:或许你根本不知道任何模式,不考虑任何模式,却写着最优秀的代码,即使以"模式专家"的角度来看,都是最佳的设计,不得不说是"最佳的模式实践",这

head first 设计模式读书笔记 之 策略模式

作为一个php开发者,深知曾经很多程序员都鄙视php,为什么呢?因为他们认为php的语法是dirty的,并且由于开发者水平参差不齐导致php的代码更加乱上加乱,维护起来简直一坨shit一样.随着php加入了面向对象的阵型之后,很多开发者开始使用了oop思想来写代码,php也变得越来越标准,越来越规范.而其中,设计模式起到了不小的作用.最近老大找我谈话,说php这边的开发模块耦合度过高,代码感觉质量不高,想来一次代码重构行动.我对代码重构也是一知半解,而代码重构的基础就是去了解设计模式,于是我翻起

设计模式学习笔记--工厂方法模式

学习过简单工厂模式,感觉很好用.在创建对象时,可以将复杂的初始化操作从客户端分离出来,简化客户端代码.大大的减少了代码修改的难度.而且可以通过参数不同,创建不同的对象. 但是简单工厂模式也有一些弊端,违背了开放--封闭原则.即如果我们增加了一个产品,对应的工厂也要进行修改,即switch---case中要新增加一些分支条件,不利于扩展.所以就有了下面的工厂方法模式: 工厂方法模式:定义了一个用于创建对象的接口,子类决定实例化哪一个类,工厂方法模式使一个类的实例化延迟到子类. // 设计模式Dem

大话设计模式读书笔记--2.策略模式

面向对象的编程,并不是类越多越好,类的划分是为了封装,但分类的基础是抽象,具有相同属性和功能的对象的抽象集合才是类 定义 它定义了算法家族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化,不会影响到使用算法的客户 模式结构 Strategy: 定义所有支持算法的公共接口 ConcreteStrategy: 封装了具体的算法或行为,也就是具体的策略 Context:是算法对象工厂, 维护一个Strategy对象的引用, 产生具体算法对象 模式实现 场景:模拟商城收银软件,营业员根据客户所