码迷,mamicode.com
首页 > 其他好文 > 详细

策略模式

时间:2018-03-13 22:52:08      阅读:230      评论:0      收藏:0      [点我收藏+]

标签:illegal   条件   anti   使用场景   不同的   ignore   扩展   state   instant   

什么是策略模式?

策略模式是一种用来封装变化, 让算法的变化不影响使用的客户,并且可以灵活的替换各种算法(概念这种东西太死板了,要理解它,灵活使用它, 而不是背过它 !!)

使用场景

平时我们登录网站的时候可以看到有多种选择, 普通的用户密码登录、微信登录、qq登录等, 这里我们就用策略模式(实际上采用简单工厂也可以)来模拟这种情景。

策略模式实现

  • 注: 这里采用接口实现,有些书籍可能是采用抽象类, 模式要活用、活用、活用
  • 微信登录、qq登录等实体类及接口
public interface LoginWay {
    Boolean login();
}

public class WeChat implements LoginWay {
    
    @Override
    public Boolean login() {
        System.out.println("欢迎使用微信登录, 登录成功");
        return true;
    }
}

public class QQ implements LoginWay {

    @Override
    public Boolean login() {
        System.out.println("欢迎使用qq登录, 登录成功");
        return true;
    }
}
  • 策略模式实现

    public class LoginStategy {
    LoginWay loginWay;
    
    public LoginStategy(LoginWay loginWay) {
        this.loginWay = loginWay;
    }
    
    public Boolean login(){
        return loginWay.login();
    }
    }
  • 策略模式客户端使用

    public class LoginStategyTest {
    
    /**
     * 基础的策略模式需要在客户端中选择策略, 可以结合简单工厂模式将策略封装在策略类中
     * 如果将具体类创建过程封装到LoginStategy, 实际上在客户端只会了解LoginStategy, 相对于单独的简单工厂方法降低了耦合度
     *
     * 扩展一种新的方式:
     *  1. 扩展一个新的登录方式(loginway)
     *  2. UI端增加一个选项
     *  3. 客户端需要增加一个分支(如果采用简单工厂也只是把客户端的逻辑封装在了工厂中, 一样需要增加分支(如果再结合反射, 完美))
     */
    @Test
    public void testLogin() {
    
        //界面选择登录方式
        String loginWay = "wechat";
        LoginStategy loginStategy ;
        if(loginWay.equalsIgnoreCase("wechat")){
            loginStategy = new LoginStategy(new WeChat());
        }else if(loginWay.equalsIgnoreCase("qq")){
            loginStategy = new LoginStategy(new QQ());
        }else if(loginWay.equalsIgnoreCase("github")){
            loginStategy = new LoginStategy(new GitHub());
        }else {
            loginStategy = new LoginStategy(new Normal());
        }
        assertTrue(loginStategy.login());
        //新加一个登录方式, 需要修改客户端的分支条件
    
    }
    }
  • 简单工厂模式

    public class LoginWayFactory {
    
      //如果采用简单工厂实现 登录方式选择, 也只是把客户端的判断放到了后台而已
      // 所以我们可以约定好传入参数的格式, 这样就可以利用反射去掉if switch的判断逻辑
    public LoginWay createLoginWay(String loginWay) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        if(loginWay.equalsIgnoreCase("wechat")){
            return new WeChat();
        }else if(loginWay.equalsIgnoreCase("qq")){
            return new QQ();
        }else if(loginWay.equalsIgnoreCase("github")){
            return new GitHub();
        }else {
            return new Normal();
        }
    
        //利用反射 根据传入类型生成实体类
        //  loginWay = "Normal";
        //  Class<?> clazz = Class.forName("com.lx.designpattern.loginway." + loginWay);
        //  return (LoginWay) clazz.newInstance();
    
    }
    }

    简单工厂客户端使用

    public class LoginWayFactoryTest {
    /**
     * 使用简单工厂方式 我们在客户端我们需要了解到俩个类 LoginWayFactory LoginWay 参与到编译中
     *
     */
    @Test
    public void testLogin() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
    
        LoginWayFactory factory = new LoginWayFactory();
        //界面选择不同的登录方式
        LoginWay loginWay = factory.createLoginWay("wechat");
        assertTrue(loginWay.login());
        loginWay = factory.createLoginWay("qq");
        assertTrue(loginWay.login());
    
        //新加一个登录方式, 需要修改factory总的分支条件, 需要loginwayfactory参与编译
        loginWay = factory.createLoginWay("githubxx");
        assertTrue(loginWay.login());
    }
    }

    策略模式与简单工厂混合使用

    public LoginStategy(String loginWay) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
    //        if(loginWay.equalsIgnoreCase("wechat")){
    //            this.loginWay = new WeChat();
    //        }else if(loginWay.equalsIgnoreCase("qq")){
    //            this.loginWay = new QQ();
    //        }else if(loginWay.equalsIgnoreCase("github")){
    //            this.loginWay = new GitHub();
    //        }else {
    //            this.loginWay = new Normal();
    //        }
        Class<?> clazz = Class.forName("com.lx.designpattern.loginway." + loginWay);
        this.loginWay = (LoginWay) clazz.newInstance();
    }

    测试与简单工厂结合后策略模式

      /**
     * 测试采用策略模式与简单工厂反射结合
     */
    @Test
    public void testLogin2() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
    
        //约定好登录方式标识,传入的标识直接就是类名
        String loginWay = "WeChat";
        LoginStategy loginStategy = new LoginStategy(loginWay);
        assertTrue(loginStategy.login());
    
    }

使用策略模式与简单工厂结合的好处:

  • 如果使用最后一种方式, 如果需要扩展一种新的方式,只需要扩展具体的实现类, 并且在ui上约定好返回字符串即可
  • 再次强调, 设计模式是要灵活,混合的使用, 设计模式是思想, 是为了更方便优雅的扩展、封装

代码路径

https://github.com/offline7LY/designpattern.git

策略模式

标签:illegal   条件   anti   使用场景   不同的   ignore   扩展   state   instant   

原文地址:https://www.cnblogs.com/qq347061329/p/8562620.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!