浅谈设计模式-策略模式

书接上回,本篇讲一下行为型模式-策略模式

策略设计模式

定义:定义一系列算法,把它们一个个封装起来,并且使它们可相互替换。让算法能独立于客户端。

UML图

IStrategy:策略接口,定制策略算法基本规则。

ConcreteStrategyA/B:具体策略实现,实现IStrategy接口,不同实现类,实现不同算法。

Context:上下文,复杂与具体策略类交互。

/**
 * 策略接口
 */

public interface IStrategy {

    /**
     * 策略算法逻辑
     */
    void doLogic();
}
/**
 * 策略实现类
 */
public class ConcreteStrategyA  implements IStrategy{
    @Override
    public void doLogic() {
        System.out.println("具体策略实现A");
    }
}
/**
 * 策略实现类
 */
public class ConcreteStrategyB implements IStrategy{
    @Override
    public void doLogic() {
        System.out.println("具体策略实现B");
    }
}
/**
 * 上下文环境,负责与策略类交互
 */
public class Context {

    //指定的执行策略对象
    private IStrategy strategy;

    public Context(IStrategy strategy) {
        this.strategy = strategy;
    }
    //执行策略
    void strategyExecute(){
        strategy.doLogic();
    }
}
public class App {

    public static void main(String[] args) {
        Context context = new Context(new ConcreteStrategyA());
        context.strategyExecute();
        context = new Context(new ConcreteStrategyB());
        context.strategyExecute();
    }
}

解析

在App测试类中,通过new不同的策略实现类对象,Context类执行的结果不一致,但好处在于,后续如果想拓展出现的算法,只需要创建新的策略实现类即可,这妥妥的开闭原则

案例分析

需求:设计一套支付系统,支持微信支付,支付宝支付,银联支付

分析

从需求上看,支付有3种实现方式微信,支付宝,银联,用户在某一时刻支付时,需要选择这3种支付中的一种,并保证支付能成功。从设计上考虑,3种支付都属于支付问题,算法主体一致,实现各有不同,这是可以使用策略模式实现。

支付策略接口:负责定制支付算法实现规则(定义支付方法骨架)

微信,支付宝,银联:实现各自的支付算法逻辑。

上下文:用户付款时,根据需要选择不同的支付方式。

UML图

IPayStrategy

/**
 * 支付策略
 */
public interface IPayStrategy {
    //常量标记
    int  PAY_WECHAT = 1;
    int  PAY_ALI = 2;
    int  PAY_UNION = 3;
    /**
     * 支付
     */
    void pay(int money);
}

UnionStrategy  

//银联支付
public class UnionStrategy implements IPayStrategy{
    @Override
    public void pay(int money) {
        System.out.println("银联支付:" + money);
    }
}

WeChatPayStrategy   

//微信支付
public class WeChatPayStrategy  implements IPayStrategy{
    @Override
    public void pay(int money) {
        System.out.println("微信支付:" + money);
    }
}

AliPayStrategy 


//支付宝支付
public class AliPayStrategy implements IPayStrategy{
    @Override
    public void pay(int money) {
        System.out.println("支付宝支付:" + money);
    }
}

MeituanApp  

/**
 * 美团App
 */
public class MeituanApp {
    //订单支付
    public void orderPay(int type, int money){

        if(IPayStrategy.PAY_WECHAT == type){
            new WeChatPayStrategy().pay(money);
        }else if(IPayStrategy.PAY_ALI == type){
            new AliPayStrategy().pay(money);
        }else if(IPayStrategy.PAY_UNION == type){
            new UnionStrategy().pay(money);
        }else{
            throw new RuntimeException("支付失败");
        }
    }
}
public class App {

    public static void main(String[] args) {
        //模拟用户支付
        MeituanApp app = new MeituanApp();
        //模拟用户挑选支付宝支付
        app.orderPay(IPayStrategy.PAY_ALI, 100);
        //模拟用户挑选微信支付
        app.orderPay(IPayStrategy.PAY_WECHAT, 100);
        //模拟用户挑选银联支付
        app.orderPay(IPayStrategy.PAY_UNION, 100);

    }
}

解析

上面美团MeituanApp 是支付策略实现的关键,根据用户不同选择,使用不同的支付系统。但是,使用if...else if...else 作判断,不算太优雅,可以适当转换一下。

/**
 * 美团App
 */
public class MeituanApp { 
    //缓存支付策略
    private static Map<Integer, IPayStrategy> STRATEGY_MAP = new HashMap<>();
    static{
        STRATEGY_MAP.put(IPayStrategy.PAY_WECHAT, new WeChatPayStrategy());
        STRATEGY_MAP.put(IPayStrategy.PAY_ALI, new AliPayStrategy());
        STRATEGY_MAP.put(IPayStrategy.PAY_UNION, new UnionStrategy());
    }
    //订单支付
    public void orderPay(int type, int money){
        IPayStrategy payStrategy = STRATEGY_MAP.get(type);
        if(payStrategy != null){
            payStrategy.pay(money);
        }else{
            throw new RuntimeException("支付失败");
        }
    }
}

适用场景

1>系统有很多类,而他们的区别仅仅在于它们的行为不同(实现算法)。

2>一个系统需要从多种执行策略中选择一种执行。

优缺点

优点

1>符合开闭原则,能优雅实现对修改关闭,对拓展开发

2>可以避免使用多重条件转移语句(比如:if..else if..else使用)

3>提高算法的保密性和安全性(算法封装在类内部)

缺点

1>使用策略的客户端需要知道所有策略类

2>会生成很多策略类

开发案例

JDK中的Compartor比较接口

Compartor接口就是一个策略接口, 每一次比较规则就是一个策略实现

比如:集合倒序排

 Collections.sort(Arrays.asList(1, 2, 3, 4, 5), (v1, v2)->v2.compareTo(v1));

Spring中的资源文件加载

Resource 资源加载类,它也是一个策略接口类,有不同的加载实现

public interface Resource extends InputStreamSource {
    boolean exists();

    default boolean isReadable() {
        return this.exists();
    }

    default boolean isOpen() {
        return false;
    }

    default boolean isFile() {
        return false;
    }

    URL getURL() throws IOException;

    URI getURI() throws IOException;
}

实现类1:ClassPathResource 

public class ClassPathResource extends AbstractFileResolvingResource {
	public ClassPathResource(String path, @Nullable ClassLoader classLoader) {
		Assert.notNull(path, "Path must not be null");
		String pathToUse = StringUtils.cleanPath(path);
		if (pathToUse.startsWith("/")) {
			pathToUse = pathToUse.substring(1);
		}
		this.path = pathToUse;
		this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
	}
}

实现类2:UrlResource 

public class UrlResource extends AbstractFileResolvingResource {
    public UrlResource(URI uri) throws MalformedURLException {
		Assert.notNull(uri, "URI must not be null");
		this.uri = uri;
		this.url = uri.toURL();
	}
}

总结

策略模式本质:分离算法,选择性实现

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浪飞yes

我对钱没兴趣~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值