《Head First设计模式》之策略模式

时间:2021-12-03 21:57:14

   前段时间研究了数据结构,最近一段时间在看设计模式的书,感觉还是有些收获的,所以不才妄自拙笔打算写些设计模式的博客,和志同道合的朋友一起学习。

   如果看过了《大话设计模式》和《head first 设计模式》的话,本文参考这两本书,个人推荐head first的书,因为它用的语言是Java,大话用的是C#,主要原因还是head first的书总结的更全一些,特别是思考的过程和there are no dumb questions等感觉特别有意思,对比策略模式的例子的话还是大话的书中的例子更形象,更容易理解。对于策略模式,大话书上用的是抽象类的方式,而head first用的是接口的方式,感觉用接口的方式更符合策略模式,因为Java和C#语言都不支持多继承,如果这个类需要继承某个类的特性的话,就……

   大话中的例子说的是对于商场打折的促销活动,正常情况是全额,节假日可能对商品打八折、可能打n折,可能满300送100,可能满200送50……

   没有学设计模式之前,我们就是对于每一种不同的促销方式分别写一个类,就是完全用具体类实现,相信学习过策略模式之后,我们知道应该把这样的算法族封装起来,我改写了大话书上的实现方式,不过原理都一样。

   第一个和大家分享的设计模式是策略模式:定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。看图就明白了

《Head First设计模式》之策略模式

而我实现正是参考这张图

首先是抽象出算法来的策略类

package mystrategy;

public interface Promotion {
public double discount(double money);
}
然后是三种不同价格的具体策略类

全价类

package mystrategy;

public class FullPrice implements Promotion{

public double discount(double money) {
return money;
}
}
打折价类

package mystrategy;

public class DiscountPrice implements Promotion{
private final double FACOTR = 0.8;

public double discount(double money) {
return money*FACOTR;
}
}
返利类,这里只是简单的实现,和大话还是有些出入

package mystrategy;

public class ReturnPrice implements Promotion {
private final double MONEY_CONDITION = 300;
private final double MONEY_RETURN = 100;

public double discount(double money) {
if(money>MONEY_CONDITION){
return money-MONEY_RETURN;
}
return money;
}
}
然后是Context上下文,其实就是用来对策略类的引用,这里是接口

package mystrategy;

public class Context {
private Promotion promotion;

public void setPromotion(Promotion promotion) {
this.promotion = promotion;
}

public double getPayMoney(double money){
return promotion.discount(money);
}
}
最后是测试类

package mystrategy;

import java.util.Scanner;

public class TestStrategy {
public static void main(String[] args) {
int choice = 0;
double money;
Context context = new Context();
Scanner reader = new Scanner(System.in);
while(choice!=-1){
money = 400;
choice = reader.nextInt();
switch (choice) {
case 1:
System.out.print("全价:");
context.setPromotion(new FullPrice());
break;
case 2:
System.out.print("折扣价(0.8折):");
context.setPromotion(new DiscountPrice());
break;
case 3:
System.out.print("超过300返100:");
context.setPromotion(new ReturnPrice());
break;
default:
break;
}
money = context.getPayMoney(money);
System.out.println(money);
}
reader.close();
}
}

其实不管我们用的是接口,还是抽象类,原理相同。

head first对此总结了三条设计原则

1.找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起

2.针对接口编程,而不是针对实现编程。

3.多用组合,少用继承


    感觉策略模式其实就是针对第二条来说的,策略模式就是实现一个接口,当然这里取的是广义的意思,实现一个接口泛指实现某个超类型(可以是类或接口)的某个方法,策略模式利用面向接口编程的特性,在运行时采取了多态,这样就不会依赖于具体类,如果用传统的方法,必然要和具体类挂钩。

   策略模式的实际应用,spring对于底层资源的访问全部依赖于resource接口,而这个接口就是一个典型的策略接口,他的实现类有UrlResource、ClassPathResource、FileSystemResouce、InputStreamResource等,不同的实现类代表了不同的资源访问策略。,而在spring中等同于策略模式中的Context类是ResouceLoader接口,该接口中有方法:Resource getResource(String location)。相信用过spring的朋友一定知道,我们获得应用上下文都是这样

<span style="font-family:Microsoft YaHei;">ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");</span>

其实ApplicationContext接口继承了ResourcePatternResolver,而ResourcePatternResolver继承了ResourceLoader接口,这里的ApplicationContext就相当于上面的主类。


1.先看Resource接口,相当于Strategy策略类

《Head First设计模式》之策略模式



2.这里只列出Resource接口其中的一个实现类UrlResource,其中具体类UrlResource继承抽象类AbstractFileResolvingResource,抽象类AbstractFileResolvingResource继承抽象类AbstractResource,抽象类AbstractResource实现Resource接口,相当于UrlRsource间接实现了Resource,相当于策略模式中的具体策略类
《Head First设计模式》之策略模式

3.再看ResourceLoader接口,主要是Resource getResource(String location);方法,相当于Context上下文

《Head First设计模式》之策略模式



如果文章有什么错误或者有什么建议,欢迎提出,大家共同交流,一起进步

文章转载请注明出处,请尊重知识产权