关于设计模式:设计模式面试小炒策略和工厂模式替代业务场景中复杂的ifelse

49次阅读

共计 5979 个字符,预计需要花费 15 分钟才能阅读完成。

《设计模式面试小炒》策略和工厂模式代替业务场景中简单的 ifelse

我是肥哥,一名不业余的面试官!

我是囧囧,一名踊跃找工作的小菜鸟!

囧囧示意:小白面试最怕的就是面试官问的知识点太抽象,本人无奈疾速定位到关键问题点!!!


本期次要面试考点

面试官考点之如何用设计模式替换业务场景中简单的 ifelse?

VIP 类型

import java.util.Objects;

/**
 * @author: 欢送关注喂信公猪号:囧么肥事
 * @date: 2021/12/16
 * @email: jiongmefeishi@163.com
 *
 * 会员类型
 */
public enum VIPEnums {GOLD(1, "黄金会员"),
    STAR(2, "星钻会员"),
    SPORTS(3, "体育会员"),
    FUN_VIP(4, "FUN 会员");

    private final int code;
    private final String desc;

    VIPEnums(int code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    public int getCode() {return code;}

    public String getDesc() {return desc;}

    public static VIPEnums getByCode(Integer code) {for (VIPEnums s : VIPEnums.values()) {if (Objects.equals(s.getCode(), code)) {return s;}
        }
        return null;
    }
}

VIP 实体

/**
 * @author: 欢送关注喂信公猪号:囧么肥事
 * @date: 2021/12/16
 * @email: jiongmeifeishi@163.com
 *
 * vip
 */
public class VIP {

    private VIPEnums vipType;

    // TODO VIP 其余属性 id, name ...

    public VIP() {}

    public VIP(VIPEnums vipType) {this.vipType = vipType;}

    public VIPEnums getVipType() {return vipType;}

    public void setVipType(VIPEnums vipType) {this.vipType = vipType;}
}

if-else 模式

// if-else 模式
public class App {public static void main( String[] args ) {

        // 黄金会员
        VIP vip = new VIP(VIPEnums.GOLD);

        if (vip.getVipType().getCode() == VIPEnums.GOLD.getCode()) {// TODO 黄金会员权利} else if (vip.getVipType().getCode() == VIPEnums.STAR.getCode()) {// TODO 星钻会员权利} else if (vip.getVipType().getCode() == VIPEnums.SPORTS.getCode()) {// TODO 体育会员权利} else if (vip.getVipType().getCode() == VIPEnums.FUN_VIP.getCode()) {// TODO FUN 会员权利} else {// TODO 其余会员...}

    }
}

策略模式

VIP 策略接口

/**
 * @author: 欢送关注喂信公猪号:囧么肥事
 * @date: 2021/12/16
 * @email: jiongmefeishi@163.com
 * VIP 策略接口
 */
public interface VIPStrategy {

    // VIP 具备的权利
    void equity();}

策略接口具体实现类 - 黄金会员

/**
 * @author: 欢送关注喂信公猪号:囧么肥事
 * @date: 2021/12/16
 * @email: jiongmefeishi@163.com
 *
 * 策略接口具体实现类 - 黄金会员
 */
public class GoldVIPStrategyImpl implements VIPStrategy {

    @Override
    public void equity() {// TODO 黄金会员具备的具体权利}
}

策略接口具体实现类 - 星钻会员

/**
 * @author: 欢送关注喂信公猪号:囧么肥事
 * @date: 2021/12/16
 * @email: jiongmefeishi@163.com
 *
 * 策略接口具体实现类 - 星钻会员
 */
public class StarVIPStrategyImpl implements VIPStrategy {

    @Override
    public void equity() {// TODO 星钻会员具备的具体权利}
}

策略接口具体实现类 - 体育会员

/**
 * @author: 欢送关注喂信公猪号:囧么肥事
 * @date: 2021/12/16
 * @email: jiongmefeishi@163.com
 *
 * 策略接口具体实现类 - 体育会员
 */
public class SportsVIPStrategyImpl implements VIPStrategy {

    @Override
    public void equity() {// TODO 体育会员具备的具体权利}
}

策略接口具体实现类 -FUN 会员

/**
 * @author: 欢送关注喂信公猪号:囧么肥事
 * @date: 2021/12/16
 * @email: jiongmefeishi@163.com
 *
 * 策略接口具体实现类 -FUN 会员
 */
public class FunVIPStrategyImpl implements VIPStrategy {

    @Override
    public void equity() {// TODO FUN 会员具备的具体权利}
}

策略上下文类

/**
 * @author: 欢送关注喂信公猪号:囧么肥事
 * @date: 2021/12/16
 * @email: jiongmefeishi@163.com
 *
 * 策略上下文类(vip 策略接口的持有者)
 */
public class VIPStrategyContext {

    private VIPStrategy vipStrategy;

    // 设置 VIP 策略
    public void setVipStrategy(VIPStrategy vipStrategy) {this.vipStrategy = vipStrategy;}

    // 执行 VIP 权利
    public void handle() {if (vipStrategy != null) {vipStrategy.equity();
        }
    }
}

策略工厂

/**
 * @author: 欢送关注喂信公猪号:囧么肥事
 * @date: 2021/12/16
 * @email: jiongmefeishi@163.com
 *
 * VIP 策略工厂
 */
public class VIPStrategyFactory {private VIPStrategyFactory() { }

    public static VIPStrategy getVipStrategy(VIP vip) {
        VIPStrategy vipStrategy = null;
        
        if (vip.getVipType().getCode() == VIPEnums.GOLD.getCode()) {
            // 黄金会员策略实现类
            vipStrategy = new GoldVIPStrategyImpl();} else if (vip.getVipType().getCode() == VIPEnums.STAR.getCode()) {
            // 星钻会员策略实现类
            vipStrategy = new StarVIPStrategyImpl();} else if (vip.getVipType().getCode() == VIPEnums.SPORTS.getCode()) {
            // 体育会员策略实现类
            vipStrategy = new SportsVIPStrategyImpl();} else if (vip.getVipType().getCode() == VIPEnums.FUN_VIP.getCode()) {
            // FUN 会员策略实现类
            vipStrategy = new FunVIPStrategyImpl();} else {// 其余会员...}

        return vipStrategy;
    }
}

模仿会员登录获取权利

/**
 * @author: 欢送关注喂信公猪号:囧么肥事
 * @date: 2021/12/16
 * @email: jiongmefeishi@163.com
 *
 * 模仿会员登录获取权利
 */
public class TestStrategy {public static void main(String[] args) {

        // 黄金会员
        VIP vip = new VIP(VIPEnums.GOLD);

        // 策略上下文,执行者
        VIPStrategyContext context = new VIPStrategyContext();

        // 依据会员类型,获取会员具体策略,获取黄金会员策略
        VIPStrategy strategy = VIPStrategyFactory.getVipStrategy(vip);

        // 绑定给执行者
        context.setVipStrategy(strategy);

        // 执行黄金会员的策略,黄金权利
        context.handle();}
}

咱们晓得,策略模式的自身设计进去的目标是封装一系列的算法,这些算法都具备共性,能够互相替换,算法独立于应用它的客户端独立变动,客户端不须要理解关注算法的具体实现,客户端仅仅依赖于策略接口。

通过应用策略模式和工厂模式联合,是不是感觉变得高大上起来了呢?😇

当然了,最次要的是程序的扩大来说更不便了一些,更合乎开闭准则,凋谢扩大,敞开批改。无论新增多少种新类型的会员,每个人只须要去继承策略接口,实现新会员应有的权利即可。

留神,尽管利于扩大,然而策略模式的毛病也很显著,策略工厂在创立具体的策略实现类的时候,还是书写大量的 if-else 去进行判断,如图

有小伙伴就说了这和不应用策略模式和工厂模式仿佛差不多???

抽出一个办法或者封装成一个对象去调用岂不是更简略???

接下来,咱们就说说 如何优化策略工厂

首先,咱们的工厂,是依据以后传入的用户的会员类型,判断后,返回相应的策略实现类,那么能够借助汇合来存储实现类,会员类型作为 key,将所有的会员策略都注册到 map 中。须要留神的是,日常开发基于 Spring 进行 bean 治理,下面须要创立的策略类,当然都是心愿被 Spring 动静托管,而不是咱们本人去一个个的 new 出实例。

问题是,如何去实现策略类通过 spring 进行托管注册?

Spring 种提供的 InitializingBean 接口,这个接口为 Bean 提供了属性初始化后的解决办法,它只包含 afterPropertiesSet 办法,但凡继承该接口的类,在 bean 的属性初始化后都会执行该办法。咱们利用此办法把 Spring 通过 IOC 创立进去的 Bean 注册 Map 中。

革新策略工厂


import org.example.model.VIP;
import org.example.strategy.VIPStrategy;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author: 欢送关注喂信公猪号:囧么肥事
 * @date: 2021/12/16
 * @email: jiongmefeishi@163.com
 * <p>
 * VIP 策略工厂
 */
public class VIPStrategyFactory {

    // 存储策略类实例
    public static Map<Integer, VIPStrategy> strategyMap = new ConcurrentHashMap<>();

    private VIPStrategyFactory() {}

    public static VIPStrategy getVipStrategy(VIP vip) {if (vip == null) {return null;}
        return strategyMap.get(vip.getVipType().getCode());
    }
}

革新策略类,在 bean 属性初始化后,将实例对象注册到工厂类中的 map

以黄金会员为例:

import org.example.factory.VIPStrategyFactory;
import org.example.model.VIPEnums;
import org.example.strategy.VIPStrategy;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;

/**
 * @author: 欢送关注喂信公猪号:囧么肥事
 * @date: 2021/12/16
 * @email: jiongmefeishi@163.com
 *
 * 策略接口具体实现类 - 黄金会员
 */
@Service
public class GoldVIPStrategyImpl implements VIPStrategy, InitializingBean {

    @Override
    public void equity() {
        // TODO 黄金会员具备的具体权利
        System.out.println("黄金会员具备的具体权利");
    }

    @Override
    public void afterPropertiesSet() throws Exception {VIPStrategyFactory.strategyMap.put(VIPEnums.GOLD.getCode(), new GoldVIPStrategyImpl());
    }
}

通过策略模式、工厂模式以及 Spring 的 InitializingBean 接口,算是解决了大量的 if else,后续新 VIP 呈现也更容易扩大,当然了,这里只是对于设计模式思维的一个简略的示例,理论利用开发中,还是要依据具体的业务场景灵便变通。有须要的小伙伴也能够本人手动模仿一些场景,比方奶茶店各种奶茶新品等等。如果想用囧囧的示例,可公猪号上回复 220110 自行导入示例运行即可。

留神:学习软件设计准则,千万不能造成强迫症。当碰到业务简单的场景时,须要随机应变。

学习设计准则是学习设计模式的根底。在理论开发过程中,并不是肯定要求所有代码都遵循设计准则,而是要综合思考人力、工夫、老本、品质,不刻意追求完满,要在适当的场景遵循设计准则。这体现的是一种均衡取舍,能够帮忙咱们设计出更加优雅的代码构造。

设计模式其实也是一门艺术。设计模式源于生存,不要为了套用设计模式而应用设计模式。

喜爱的小伙伴,欢送点赞珍藏关注

正文完
 0