七:策略模式(不同等级会员打折算法)
定义:策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化;
策略模式在LZ第一次接触到的时候,LZ是这么理解的,就是如果我们想往一个方法当中插入随便一段代码的话,就是策略模式。即如下形式。
public class MyClass { public void myMethod(){ System.out.println("方法里的代码"); //LZ想在这插入一段代码,而且这个代码是可以改变的,想怎么变就怎么变 System.out.println("方法里的代码"); } }
在JAVA中,接口可以满足LZ的这一过分要求,我们可以设计一个接口,并当做参数传进去,就能达到这个效果了。我们来看,先定义一个接口。
public interface MyInterface { //我想插入的代码 void insertCode(); }
将原来的类改成这样,传递一个接口进去。
public class MyClass { public void myMethod(MyInterface myInterface){ System.out.println("方法里的代码"); //你看我是不是插进来一段代码?而且这段代码是可以随便改变的 myInterface.insertCode(); System.out.println("方法里的代码"); } }
class InsertCode1 implements MyInterface{ public void insertCode() { System.out.println("我想插进去的代码,第一种"); } } class InsertCode2 implements MyInterface{ public void insertCode() { System.out.println("我想插进去的代码,第二种"); } }
这样我们在调用myMethod方法时就可以随意往里面插入代码了,比如。
//客户端调用 public class Client { public static void main(String[] args) { MyClass myClass = new MyClass(); myClass.myMethod(new InsertCode1()); System.out.println("--------------------"); myClass.myMethod(new InsertCode2()); } }
那么运行出来的结果就是我们成功的将两端代码插入到了myMethod方法中,以上所讲的算是JAVA中一种技术层面的实现,就是传入一个接口,封装代码。那么既然谈到设计模式,就要有设计模式的应用场景,有关策略模式,所产生的形式就和上述是一模一样的,只是我们适当的给予模式的应用场景,就会让它变的更有价值。
上面的例子代码清晰但却理解起来很生硬,下面LZ举一个具有实际意义的例子。
2. 就比如我们要做一个商店的收银系统,这个商店有普通顾客,会员,超级会员以及金牌会员的区别,针对各个顾客,有不同的打折方式,并且一个顾客每在商店消费1000就增加一个级别,那么我们就可以使用策略模式,因为策略模式描述的就是算法的不同,而且这个算法往往非常繁多,并且可能需要经常性的互相替换。
这里我们举例就采用最简单的,以上四种顾客分别采用原价,八折,七折和半价的收钱方式。
那么我们首先要有一个计算价格的策略接口,如下。
public interface CalPrice {
//根据原价返回一个最终的价格
Double calPrice(Double originalPrice);
}
下面我们给出四个计算方式。
class Common implements CalPrice{ public Double calPrice(Double originalPrice) { return originalPrice; } } class Vip implements CalPrice{ public Double calPrice(Double originalPrice) { return originalPrice * 0.8; } } class SuperVip implements CalPrice{ public Double calPrice(Double originalPrice) { return originalPrice * 0.7; } } class GoldVip implements CalPrice{ public Double calPrice(Double originalPrice) { return originalPrice * 0.5; } }
以上四种计算方式非常清晰,分别是原价,八折,七折和半价。
下面我们看客户类,我们需要客户类帮我们完成客户升级的功能。
//客户类 public class Customer { private Double totalAmount = 0D;//客户在本商店消费的总额 private Double amount = 0D;//客户单次消费金额 private CalPrice calPrice = new Common();//每个客户都有一个计算价格的策略,初始都是普通计算,即原价 //客户购买商品,就会增加它的总额 public void buy(Double amount){ this.amount = amount; totalAmount += amount; if (totalAmount > 3000) {//3000则改为金牌会员计算方式 calPrice = new GoldVip(); }else if (totalAmount > 2000) {//类似 calPrice = new SuperVip(); }else if (totalAmount > 1000) {//类似 calPrice = new Vip(); } } //计算客户最终要付的钱 public Double calLastAmount(){ return calPrice.calPrice(amount); } }
//我们使用一个标准的简单工厂来改进一下策略模式 public class CalPriceFactory { private CalPriceFactory(){} //根据客户的总金额产生相应的策略 public static CalPrice createCalPrice(Customer customer){ if (customer.getTotalAmount() > 3000) {//3000则改为金牌会员计算方式 return new GoldVip(); }else if (customer.getTotalAmount() > 2000) {//类似 return new SuperVip(); }else if (customer.getTotalAmount() > 1000) {//类似 return new Vip(); }else { return new Common(); } } }
//客户类 public class Customer { private Double totalAmount = 0D;//客户在本商店消费的总额 private Double amount = 0D;//客户单次消费金额 private CalPrice calPrice = new Common();//每个客户都有一个计算价格的策略,初始都是普通计算,即原价 //客户购买商品,就会增加它的总额 public void buy(Double amount){ this.amount = amount; totalAmount += amount; /* 变化点,我们将策略的制定转移给了策略工厂,将这部分责任分离出去 */ calPrice = CalPriceFactory.createCalPrice(this); } //计算客户最终要付的钱 public Double calLastAmount(){ return calPrice.calPrice(amount); } public Double getTotalAmount() { return totalAmount; } public Double getAmount() { return amount; } }
下面我们看客户端调用,系统会帮我们自动调整收费策略。
//客户端调用 public class Client { public static void main(String[] args) { Customer customer = new Customer(); customer.buy(500D); System.out.println("客户需要付钱:" + customer.calLastAmount()); customer.buy(1200D); System.out.println("客户需要付钱:" + customer.calLastAmount()); customer.buy(1200D); System.out.println("客户需要付钱:" + customer.calLastAmount()); customer.buy(1200D); System.out.println("客户需要付钱:" + customer.calLastAmount()); } }
运行以后会发现,第一次是原价,第二次是八折,第三次是七折,最后一次则是半价。
我们这样设计的好处是,客户不再依赖于具体的收费策略,依赖于抽象永远是正确的。
现在比之前来讲,我们的策略模式更加灵活一点,但是相信看过LZ博文的都知道,LZ最不喜欢elseif,
所以策略模式也是有缺点的,就是当策略改变时,我们需要使用elseif去判断到底使用哪一个策略,哪怕使用简单工厂,也避免不了这一点。
比如我们又添加一类会员,那么你需要去添加elseif。再比如我们的会员现在打九折了,那么你需要添加一个九折的策略,这没问题,我们对扩展开放,但是你需要修改elseif的分支,将会员的策略从八折替换为九折,这是简单工厂的诟病,在之前已经提到过,对修改开放。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南