Java设计模式——策略模式

策略模式

1、定义

策略模式是一种行为型模式,它将对象和行为分开,将行为定义为 一个行为接口具体行为的实现

设计原则

  1. 把变化的代码从不变的代码中分离出来
  2. 针对接口编程而不是具体类(定义了策略接口)
  3. 多用组合/复合,少用继承(客户通过组合方式使用策略)
2、uml图

Java设计模式——策略模式_第1张图片

3、场景

假设在我们的商城系统中,需要实现一个优惠促销功能。其中优惠促销有以下几种规则。

  • 新客户:首单立减10元。
  • 满减券:满200,减30。
  • 折扣券:所有商品打9折。

对于这样的一个需求,我们该怎么实现呢?有同学可能会说了,加上几个if else就好了,接着噼里啪啦一顿操作,

if(user.role.equals("新用户")){
    
}else if(user.role.equale("满减卷")){
    
}else if(user.role.equale("折扣卷")){
    
}

这种写法是很简单,但仔细想想,这样写可能会有如下方面的问题。

如果优惠规则多了,类和方法会变得非常庞大,难以维护。而且维护和扩展都需要修改已有的代码,这样违反了开闭原则。
在不同时期,同样条件下的优惠力度可能也不一样。如在平常时期,新注册用户首单立减10元,在周年庆期间,新注册用户首单立减15元,过了周年庆,又变回首单立减10元。通过上边代码来实现这样的效果,需要频繁的修改if else中的代码,这样的切换方式会非常麻烦。

在我们生活中比较常见的应用模式有:

1、电商网站支付方式,一般分为银联、微信、支付宝,可以采用策略模式
2、电商网站活动方式,一般分为满减送、限时折扣、包邮活动,拼团等可以采用策略模式

  • 多个类只在算法或行为上稍有不同的场景。
  • 算法需要自由切换的场景。
  • 通过条件语句,在多分支中选取一种。
4、传统做法

案例:使用策略模式+工厂模式实现选择支付功能(微信支付,支付宝,银行卡)

1、父类
package demo;

/**
 *
 * 使用策略模式+工厂模式实现选择支付功能(微信支付,支付宝,银行卡)
 * 传统方式展示
 */
public abstract class Payment {

    /**
     * 默认微信支付
     */
    public void wxPayMent(){
        System.err.println("我是微信支付");
    }
}

2、微信支付
package demo;

public class WxPayMent extends Payment{
    @Override
    public void wxPayMent() {
        //默认微信支付
        super.wxPayMent();
    }
}
3、银联支付
package demo;

public class YlPayMent extends Payment{
    /**
     * 同理支付宝
     */
    @Override
    public void wxPayMent() {
        System.err.println("我是银联支付");
    }
}
4、支付宝支付
package demo;

/**
 * 支付宝支付
 */
public class ZfbPayMent extends Payment{

    /**
     * 显然我是支付宝支付,而父类是微信支付,这里使用父类的就不合理了,需要重写父类方法
     */
    @Override
    public void wxPayMent() {
        System.err.println("我是支付宝支付");
    }
}

5、客户端
package demo;

public class Test {
    public static void main(String[] args) {
        //使用支付宝支付
        Payment payment  =new ZfbPayMent();
        payment.wxPayMent();
        //使用银联支付
        Payment ylPayMent = new YlPayMent();
        ylPayMent.wxPayMent();
        //默认支付
        Payment wxPayMent = new WxPayMent();
        wxPayMent.wxPayMent();
    }
}

6、问题分析和解决方案
  1. 其他支付都继承了Payment,所有支付都是微信支付了,这是不合理的
  2. 上面说的1的问题,其实是继承带出来的问题,对类的局部改动,尤其超类的局部改动,会影响其他部分。
  3. 为了改进1问题。我们可以通过覆盖Payment方法来解决=》覆盖解决
  4. 问题又来了,如果我们又有一个花呗支付,这样就需要花呗支付去覆盖Payment的所有实现方法,这也是不合理的,我们可以选择我们想要的=》解决思路 策略模式
5、策略模式
1、接口
/**
 *
 * 使用策略模式+工厂模式实现选择支付功能(微信支付,支付宝,银行卡)
 * 传统方式展示
 */
public interface Payment {
    //提供支付方法,具体是什么支付由子类实现
    public void PayMent();
}

2、微信支付
public class WxPayMent implements Payment{
    @Override
    public void PayMent() {
        System.err.println("我是微信支付");
    }
}

3、银联支付
public class YlPayMent implements Payment{
    /**
     * 同理支付宝
     */
    @Override
    public void PayMent() {
        System.err.println("我是银联支付");
    }
}
5、支付宝支付
/**
 * 支付宝支付
 */
public class ZfbPayMent implements Payment{

    /**
     * 显然我是支付宝支付,而父类是微信支付,这里使用父类的就不合理了,需要重写父类方法
     */
    @Override
    public void PayMent() {
        System.err.println("我是支付宝支付");
    }
}

6、使用者
/**
 * 客户端使用者
 */
public class Client {
    //需要使用支付方法
    public Payment payment;

    public void setPayment(Payment payment) {
        this.payment = payment;
    }

    //提供使用支付方法
    public void clientPayment(){
        //代码实现了分离
        payment.PayMent();
    }
}
7、微信使用者
//使用微信提供的支付方法
public class WxClient extends Client{
    public WxClient(){
        payment = new WxPayMent();
    }
}

8、支付宝使用者
//使用支付宝提供的支付方法
public class ZfbClient extends Client{
    public ZfbClient(){
        payment = new ZfbPayMent();
    }
}
9、客户端使用者
public class Test {
    public static void main(String[] args) {
        /**
         * 动态运行修改
         */
        Client client = new Client();
        Payment wxPayMent = new WxPayMent();
        client.setPayment(wxPayMent);
        client.clientPayment();
        System.err.println("我动态被修改了");
        ZfbPayMent zfbPayMent = new ZfbPayMent();
        client.setPayment(zfbPayMent);
        client.clientPayment();

        /**
         * 选择一种支付方式(这里应该由前端传过来,再使用工厂模式进行处理选择,不然这里还得用if判断,可维护性差)
         * if("微信支付"){
         * Client wxClient = new WxClient();
         * }else if("支付宝支付"){
         * Client wxClient = new ZfbClient();
         * }
         */
        Client wxClient = new WxClient();
        wxClient.clientPayment();
    }
}

10、简单工厂模式
/**
 * 简单工厂模式
 */
public class SimplePayMentFactory {
    public static Client getPayMent(String payment){
        if("微信支付".equals(payment)){
            return new WxClient();
        }else if("支付宝支付".equals(payment)){
            return new ZfbClient();
        }else{
            return null;
        }
    }
}
11、客户端使用者
 /**
         * 简单工厂模式
         * 使用工厂模式处理选择支付方式(前端传入具体支付方式)
         */
        Client client2 = SimplePayMentFactory.getPayMent("支付宝支付");
        client2.clientPayment();

        /**
         * 总结 使用设计模式在以上代码中优化了多重判断和new对象了,
         * 客户端只需要传入你需要的,其他什么都不用管了
         */
5、优缺点
1、优点

策略模式提供了对“开闭原则”的完美支持,用户可以在不 修改原有系统的基础上选择算法或行为,也可以灵活地增加 新的算法或行为。

策略模式提供了管理相关的算法族的办法。

策略模式提供了可以替换继承关系的办法。

使用策略模式可以避免使用多重条件转移语句。

2、缺点

客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
策略模式将造成产生很多策略类,可以通过使用享元模式在一 定程度上减少对象的数量

你可能感兴趣的:(java,设计模式,策略模式)