设计模式学习之策略模式

            《设计模式》这本对策略模式的定义是:定义一组算法,将每个算法都封装起来,是他们之间可以相互替换。即针对一组算法,将每个算法都封装到具有共同接口的类中,使他们可以互相相互替换,在不影响客户端的情况下发生变化。

策略模式的三个角色:

   1、环境角色(Context):承启上下文的作用,防止对策略的直接访问

   2、抽象策略(Strategy):对策略进行抽象,定义每个策略必须具有的方法和属性

   3、具体策略(Concrete Strategy):实现策略的具体操作

接下来我们通过一个具体的应用去看看吧。

1、定义一个环境角色(Context):

public class Context {
    //持有一个具体策略的对象
    private Strategy strategy;
    /**
     * 构造函数,传入一个具体策略对象
     */
    public Context(Strategy strategy){
        this.strategy = strategy;
    }
    /**
     * 策略方法
     */
    public double shoppingPay(double price){
        return strategy.shoppingPay(price);
    }
}

2、定义一个抽象策略类(Strategy),里面定义一个模拟购物付款的接口。

public interface Strategy {

	double shoppingPay(double price);

}

3、对于购物付款的方式,我们都知道有微信支付,支付宝,银联等方式,那下面就针对这三种方式定义具体付款策略(Concrete Strategy),且实现策略类抽象策略类(Strategy)接口。

//微信支付
public class WeChatPay implements Strategy {

	@Override
	public double shoppingPay(double price) {
		System.out.println("微信支付,每单优惠20元");
		return price-20;
	}

}

//支付宝支付
public class AliPay implements Strategy {

	@Override
	public double shoppingPay(double price) {
		System.out.println("支付宝支付,打8折");
		return price*0.8;
	}

}

//银联支付
public class UnionPay implements Strategy {

	@Override
	public double shoppingPay(double price) {
		System.out.println("银联支付,没有优惠");
		return price;
	}

}
	public static void main(String[] args) {
		
		Strategy strategy=new WeChatPay();
		Context context=new Context(strategy);
		double pay=context.shoppingPay(500);
		System.out.println("实际付款"+pay);
		
	}

//执行输出
微信支付,每单优惠20元
实际付款480.0

	public static void main(String[] args) {
		
		Strategy strategy=new AliPay();
		Context context=new Context(strategy);
		double pay=context.shoppingPay(500);
		System.out.println("实际付款"+pay);
		
	}

//执行输出
支付宝支付,打8折
实际付款400.0

策略模式是将使用的方法分别封装成独立的类,然后使用统一的接口管理,让客户端能够随时调用他们,并且不同的行为类之间可以相互替换。

比如有一天我们忘了带银行卡,手机也没电了,那就只能现金付款了,结合以上的案例我们只需要添加一个现金付款的实例类即可,代码如下:

public class CashPay implements Strategy {

	@Override
	public double shoppingPay(double price) {
		System.out.println("现金付款,获得一次抽奖机会");
		return price;
	}

}

测试代码如下:

	public static void main(String[] args) {
		
		Strategy strategy=new CashPay();
		Context context=new Context(strategy);
		double pay=context.shoppingPay(500);
		System.out.println("实际付款"+pay);
		
	}

测试输出如下:
现金付款,获得一次抽奖机会
实际付款500.0

通过以上的扩展可以看出,应用策略模式对具体的策略进行扩展很容易,不需要改变原来的代码,但缺点是客户端调用必须知道所有的策略类的具体实现。

下面我们对上面的实例进行优化,

1、 定义一个枚举类,封装所有的支付方法

public enum PayTypeEnum {

	CASH("现金"), ALIPAY("支付宝"), WECAHTPAY("微信"), UNIONPAY("银联");
	private String payType;

	// 枚举类型的构造函数默认为private
	private PayTypeEnum(String payType) {
		this.payType = payType;
	}

	public String getPayType() {
		return payType;
	}
}

2、定义一个策略工厂,封装支付方式与策略类的关系,并且通过static代码块进行预加载

public class StrategyFactory {
	private static StrategyFactory factory = new StrategyFactory();
	private static Map<String, Strategy> map = new HashMap<>();

	private StrategyFactory() {
	}
	
	static {
		map.put(PayTypeEnum.CASH.name(), new CashPay());
		map.put(PayTypeEnum.ALIPAY.name(), new AliPay());
		map.put(PayTypeEnum.WECAHTPAY.name(), new WeChatPay());
		map.put(PayTypeEnum.UNIONPAY.name(), new UnionPay());
	}

	public Strategy getStrategy(String type) {
		return map.get(type);
	}

	public static StrategyFactory getInstance() {
		return factory;
	}
}

Strategy类修改如下:

public interface Strategy {

	double shoppingPay(double price, String type);

}

Context类修改如下:

public class Context {
	// 持有一个具体策略的对象
	private Strategy strategy;

	/**
	 * 通过对应的payType从策略工厂获取对应的策略实现类
	 */
	public double shoppingPay(double price, String payType) {
		strategy = StrategyFactory.getInstance().getStrategy(payType);
		return strategy.shoppingPay(price, payType);
	}

	public Strategy getStrategy() {
		return strategy;
	}

	public void setStrategy(Strategy strategy) {
		this.strategy = strategy;
	}
}

接口改变,对应的策略实现类也要做相应的改动,具体改动如下:

public class WeChatPay implements Strategy {

	@Override
	public double shoppingPay(double price, String type) {
		System.out.println(PayTypeEnum.WECAHTPAY.getPayType()+"支付,每单优惠20元");
		return price - 20;
	}

}

public class UnionPay implements Strategy {

	@Override
	public double shoppingPay(double price, String type) {
		System.out.println(PayTypeEnum.UNIONPAY.getPayType()+"支付,没有优惠");
		return price;
	}

}

public class AliPay implements Strategy {

	@Override
	public double shoppingPay(double price, String type) {
		System.out.println(PayTypeEnum.ALIPAY.getPayType()+"支付,打8折");
		return price * 0.8;
	}

}

public class CashPay implements Strategy {

	@Override
	public double shoppingPay(double price, String type) {
		System.out.println(PayTypeEnum.CASH.getPayType()+"付款,获得一次抽奖机会");
		return price;
	}

}

对以上4个实现类进行测试,代码如下:

public static void main(String[] args) {

		Context context = new Context();
		double alipay = context.shoppingPay(500, PayTypeEnum.ALIPAY.name());
		System.out.println("实际付款" + alipay);
		
		double wxpay = context.shoppingPay(500, PayTypeEnum.WECAHTPAY.name());
		System.out.println("实际付款" + wxpay);
		
		double unpay = context.shoppingPay(500, PayTypeEnum.UNIONPAY.name());
		System.out.println("实际付款" + unpay);
		
		double cashpay = context.shoppingPay(500, PayTypeEnum.CASH.name());
		System.out.println("实际付款" + cashpay);

	}

//执行打印输出
支付宝支付,打8折
实际付款400.0
微信支付,每单优惠20元
实际付款480.0
银联支付,没有优惠
实际付款500.0
现金付款,获得一次抽奖机会
实际付款500.0

以上代码结构如下,可直接运行:

源码地址:https://download.csdn.net/download/xuewenyong/10973322

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值