精华内容
下载资源
问答
  • ifelse优化
    千次阅读
    2021-10-08 15:17:25

    1、简介

    大量的if嵌套让代码的复杂性增高而且难以维护。本文将介绍多种解决方案。

    2、案例

    下面模拟业务逻辑,根据传入的条件作出不同的处理方式。

    public static boolean consume(PurchaseOrderMessageBody purchaseOrder) {
        PurchaseTypeEnum purchaseTypeEnum = PurchaseTypeEnum.getPurchaseTypeEnumByName(purchaseOrder.getOrderType());
        if ("XSD_PC".equals(purchaseTypeEnum.toString())) {
            CreatePurchaseHandler.handler(purchaseOrder);
        } else if ("ZYCS".equals(purchaseTypeEnum.toString())) {
            CreatePurchaseHandler.handler(purchaseOrder);
        }
        .....
        else {
            PurchaseFinishHandler.handler(purchaseOrder);
        }
    }
    

    当然也可以用switch来实现

    public static boolean consume(PurchaseOrderMessageBody purchaseOrder) {
        PurchaseTypeEnum purchaseTypeEnum = PurchaseTypeEnum.getPurchaseTypeEnumByName(purchaseOrder.getOrderType());
        switch (purchaseTypeEnum) {
            case XSD_PC:
            case ZYCS:
                return CreatePurchaseHandler.handler(purchaseOrder);
            default:
                return PurchaseFinishHandler.handler(purchaseOrder);
        }
    }
    

    随着条件越来越多,复杂性也增高,也越来越难以维护。

    3、重构

    3.1.工厂类

    我们将操作进行抽象给出一个操作接口

    public interface PurchaseTypeBasic {
        boolean purchaseHandler (PurchaseOrderMessageBody purchaseOrder);
    }
    

    然后实现创建和完成的方法

    public class CreatePurchaseHandler implements PurchaseTypeBasic {
        public boolean purchaseHandler(PurchaseOrderMessageBody purchaseOrder) {
            System.out.println("创建采购履约单");
            return true;
        }
    }
    
    public class PurchaseFinishHandler implements PurchaseTypeBasic {
        public boolean purchaseHandler(PurchaseOrderMessageBody purchaseOrder) {
            System.out.println("通知采购履约完成");
            return true;
        }
    }
    

    然后通过操作工厂提供操作

    public class OperatePurchaseTypeBasic {
        static Map<String, PurchaseTypeBasic> operationMap = new HashMap<>();
        static {
            operationMap.put("XSD_PC", new CreatePurchaseHandler());
            operationMap.put("TRIANGULAR", new PurchaseFinishHandler());
        }
        public static Optional<PurchaseTypeBasic> getOperation(String operator) {
            return Optional.ofNullable(operationMap.get(operator));
        }
    }
    

    调用

    public class PurchaseHandler {
        public static void purchaseHandler(PurchaseOrderMessageBody purchaseOrder) {
            PurchaseTypeBasic operation = OperatePurchaseTypeBasic.getOperation((purchaseOrder.getOrderType())).orElseThrow(
                    ()-> new IllegalArgumentException("Invalid Operator")
            );
            operation.purchaseHandler(purchaseOrder);
        }
    }
    
    public class Test {
        private static final String[] orderTypes = {"XSD_PC", "TRIANGULAR"};
        public static void main(String[] args) {
            PurchaseOrderMessageBody purchaseOrder = new PurchaseOrderMessageBody();
            for (String orderType : orderTypes) {
                purchaseOrder.setOrderType(orderType);
                PurchaseHandler.purchaseHandler(purchaseOrder);
            }
        }
    }
    

    新增操作只需要维护操作工厂的operationMap即可。

    3.2. 使用枚举

    在枚举中定义操作,如下:

    public enum PurchaseTypeEnum{
        XSD_PC{
            @Override
            public boolean handler(PurchaseOrderMessageBody purchaseOrder) {
                return CreatePurchaseHandler.handler(purchaseOrder);
            }
        },
        TRIANGULAR{
            @Override
            public boolean handler(PurchaseOrderMessageBody purchaseOrder) {
                return PurchaseFinishHandler.handler(purchaseOrder);
            }
        };
    
        public abstract boolean handler(PurchaseOrderMessageBody purchaseOrder);
    }
    

    不同的操作对应的逻辑不一样

    public class CreatePurchaseHandler {
        public static boolean handler(PurchaseOrderMessageBody purchaseOrder) {
            System.out.println("创建采购履约单");
            return true;
        }
    }
    
    public class CreatePurchaseHandler {
        public static boolean handler(PurchaseOrderMessageBody purchaseOrder) {
            System.out.println("创建采购履约单");
            return true;
        }
    }
    

    调用时直接传入枚举值

    public class OperateHandler {
        public boolean handler(PurchaseOrderMessageBody purchaseOrder, PurchaseTypeEnum purchaseTypeEnum) {
            return purchaseTypeEnum.handler(purchaseOrder);
        }
    }
    
    public class Test {
        private static final String[] orderTypes = {"XSD_PC", "TRIANGULAR"};
        public static void main(String[] args) {
            PurchaseOrderMessageBody purchaseOrder = new PurchaseOrderMessageBody();
            OperateHandler operateHandler = new OperateHandler();
            for (String orderType : orderTypes) {
                purchaseOrder.setOrderType(orderType);
                operateHandler.handler(purchaseOrder, PurchaseTypeEnum.valueOf(orderType));
            }
        }
    }
    

    3.3. 命令模式

    定义命令接口

    public interface Command {
        boolean execute();
    }
    

    实现不同业务

    public class CreatePurchaseCommand implements Command {
    
        private PurchaseOrderMessageBody purchaseOrder;
    
        public CreatePurchaseCommand(PurchaseOrderMessageBody purchaseOrder) {
            this.purchaseOrder = purchaseOrder;
        }
    
        @Override
        public boolean execute() {
            System.out.println("创建采购履约单");
            return true;
        }
    }
    
    public class FinishPurchaseCommand implements Command {
    
        private PurchaseOrderMessageBody purchaseOrder;
    
        public FinishPurchaseCommand(PurchaseOrderMessageBody purchaseOrder) {
            this.purchaseOrder = purchaseOrder;
        }
    
        @Override
        public boolean execute() {
            System.out.println("通知采购履约完成");
            return true;
        }
    }
    

    定义一个PurchaseExecute类,加入执行命令的方法。

    public class PurchaseExecute {
        public boolean execute(Command command) {
            return command.execute();
        }
    }
    

    测试代码

    public class Test {
        public static void main(String[] args) {
            PurchaseOrderMessageBody purchaseOrder = new PurchaseOrderMessageBody();
            purchaseOrder.setOrderType("XSD_PC");
            PurchaseExecute purchaseExecute = new PurchaseExecute();
            purchaseExecute.execute(new CreatePurchaseCommand(purchaseOrder));
        }
    }
    

    3.4. 规则引擎

    定义规则接口

    public interface Rule {
        booleanevaluate(Expression expression);
        Result getResult();
    }
    

    实现规则引擎

    public class RuleEngine {
        private static List<Rule> rules = new ArrayList<>();
        static {
            rules.add(new AddRule());
        }
        public Result process(Expression expression) {
            Rule rule = rules
                .stream()
                .filter(r -> r.evaluate(expression))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("Expression does not matches any Rule"));
            return rule.getResult();
        }
    }
    

    定义表达式

    public class Expression {
        private Integer x;
        private Integer y;
        private Operator operator; 
    }
    

    定义加法规则

    public class AddRuleimplementsRule {
        @Override
        public boolean evaluate(Expression expression) {
            boolean evalResult = false;
            if (expression.getOperator() == Operator.ADD) {
                this.result = expression.getX() + expression.getY();
                evalResult = true;
            }
            return evalResult;
        } 
    }
    

    给规则引擎传入表达式来调用

    @Test
    public void whenNumbersGivenToRuleEngine_thenReturnCorrectResult() {
        Expression expression = new Expression(5, 5, Operator.ADD);
        RuleEngine engine = new RuleEngine();
        Result result = engine.process(expression);
        assertNotNull(result);
        assertEquals(10, result.getValue());
    }
    
    更多相关内容
  • 主要介绍了Java利用策略模式优化过多if else代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • 代码中大量的 if else如何优化.doc
  • if else语句的优化

    千次阅读 2022-01-01 22:53:18
    if else语句的优化前言使用枚举使用工厂模式使用策略模式 前言 日常开发中,我们会经常遇到根据传入的值,来判断程序该走哪段代码,走哪个方法,通常我们会使用if else语句来进行判断。如果传入的值有很多中情况,...

    前言

    日常开发中,我们会经常遇到根据传入的值,来判断程序该走哪段代码,走哪个方法,通常我们会使用if else语句来进行判断。如果传入的值有很多中情况,我们也就会写很多的if else来判断,这样代码就会显得非常臃肿,难以维护。后期新加的条件不太容易扩展,测试时也要重新把整个if else语句再测试一遍,非常费时间又不方便。接下来给大家介绍几种方法,不使用if else语句也能做条件判断。

    使用枚举

    首先定义一个公用接口 RoleOperation,表示不同角色所能做的操作

    package com.gavin.enums;
    
    public interface RoleOperation {
    
        //定义一个方法来表示某个角色,有哪些op(操作)权限
        String op();
    }
    
    

    接下来我们将不同角色的情况全部交由枚举类来做,定义一个不同角色有不同权限的枚举类

    package com.gavin.enums;
    
    public enum RoleEnum implements RoleOperation{
    
        //定义一个超级管理员的操作权限(有AAA的操作权限)
        ROLE_ROOT_ADMIN {
            @Override
            public String op() {
                return "ROLE_ROOT_ADMIN:has AAA permission";
            }
        },
    
        //定义一个订单管理员的操作权限(有BBB的操作权限)
        ROLE_ORDER_ADMIN {
            @Override
            public String op() {
                return "ROLE_ORDER_ADMIN:has BBB permission";
            }
        },
    
        //定义一个普通用户的操作权限(有CCC的操作权限)
        ROLE_NORMAL {
            @Override
            public String op() {
                return "ROLE_NORMAL:has CCC permission";
            }
        };
    }
    
    

    接下来调用就变得异常简单了,一行代码就行了, if/else也灰飞烟灭了:

    package com.gavin.enums;
    
    public class JudgeRole {
    
        public static void main(String[] args) {
            String roleName = "ROLE_ROOT_ADMIN";
            String operation = RoleEnum.valueOf(roleName).op();
            System.out.println("操作权限:" + operation);
        }
    }
    
    

    在这里插入图片描述
    而且这样一来,以后我想扩充条件,只需要去枚举类中加代码即可

    使用工厂模式

    不同分支做不同的事情,很明显就提供了使用工厂模式的契机,我们只需要将不同情况单独定义好,然后去工厂类里面聚合即可。

    首先,针对不同的角色,单独定义其业务类:

    package com.gavin.factory;
    
    import com.gavin.enums.RoleOperation;
    
    public class RootAdminRole implements RoleOperation {
    
        //定义属性值
        private String roleName;
    
        //有参构造方法
        public RootAdminRole (String roleName) {
            this.roleName = roleName;
        }
    
        //实现RoleOperation接口,然后重写接口方法
        @Override
        public String op() {
            return roleName + " has AAA permission";
        }
    }
    
    
    package com.gavin.factory;
    
    import com.gavin.enums.RoleOperation;
    
    public class OrderAdminRole implements RoleOperation {
    
        //定义属性值
        private String roleName;
    
        //有参构造方法
        public OrderAdminRole(String roleName) {
            this.roleName = roleName;
        }
    
        //实现RoleOperation接口,然后重写接口方法
        @Override
        public String op() {
            return roleName + " has BBB permission";
        }
    }
    
    
    package com.gavin.factory;
    
    import com.gavin.enums.RoleOperation;
    
    public class NormalRole implements RoleOperation {
    
        //定义属性值
        private String roleName;
    
        //有参构造方法
        public NormalRole(String roleName) {
            this.roleName = roleName;
        }
    
        //实现RoleOperation接口,然后重写接口方法
        @Override
        public String op() {
            return roleName + " has CCC permission";
        }
    }
    
    

    接下来再写一个工厂类 RoleFactory对上面不同角色进行聚合:

    package com.gavin.factory;
    
    import com.gavin.enums.RoleOperation;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class RoleFactory {
    
        //定义一个Map集合,使用static修饰后会与类一起加载进堆中
        //加载顺序早于没有用static修饰的常量、变量和方法
        static Map<String, RoleOperation> map = new HashMap<>();
    
        //定义一个静态方法进行初始化
        static {
            map.put("ROLE_ROOT_ADMIN", new RootAdminRole("ROLE_ROOT_ADMIN"));
            map.put("ROLE_ORDER_ADMIN", new OrderAdminRole("ROLE_ORDER_ADMIN"));
            map.put("ROLE_NORMAL", new NormalRole("ROLE_NORMAL"));
        }
    
        //定义一个获取操作权限的静态方法,提供给其它方法调用
        public static RoleOperation getOp(String roleName) {
            return map.get(roleName);
        }
    }
    
    

    接下来借助上面这个工厂,业务代码调用也只需一行代码:

    package com.gavin.factory;
    
    public class JudgeRole02 {
    
        public static void main(String[] args) {
            /**
             * 使用工厂模式实现思路,先调用RoleFactory类中的getOp方法,找到对应的角色对象中的权限
             * 再调用该对象中的op()方法获取角色的权限信息
             */
            String roleName = "ROLE_ROOT_ADMIN";
            String operation = RoleFactory.getOp(roleName).op();
            System.out.println("操作权限:" + operation);
        }
    }
    
    

    执行结果:
    在这里插入图片描述
    这样的话以后想扩展条件也很容易,只需要增加新代码,而不需要动以前的业务代码,非常符合“开闭原则”。

    使用策略模式

    策略模式和工厂模式写起来其实区别也不大!

    在上面工厂模式代码的基础上,按照策略模式的指导思想,我们也来创建一个所谓的策略上下文类,这里命名为 RoleContext:

    package com.gavin.strategy;
    
    import com.gavin.enums.RoleOperation;
    
    public class RoleContext {
    
        //定义可更换的策略,传入不同的策略对象,业务即相应变化
        private RoleOperation roleOperation;
    
        public RoleContext(RoleOperation roleOperation) {
            this.roleOperation = roleOperation;
        }
    
        //定义获取角色权限的方法
        public String execute() {
            return roleOperation.op();
        }
    }
    
    

    很明显上面传入的参数 operation就是表示不同的“策略”。我们在业务代码里传入不同的角色,即可得到不同的操作结果:

    package com.gavin.strategy;
    
    import com.gavin.enums.RoleOperation;
    import com.gavin.factory.NormalRole;
    import com.gavin.factory.OrderAdminRole;
    import com.gavin.factory.RootAdminRole;
    
    public class JudgeRole03 {
    
        public static void main(String[] args) {
            JudgeRole03 judgeRole03 = new JudgeRole03();
            String operation = judgeRole03.judge(new RootAdminRole("ROLE_ROOT_ADMIN"));
            System.out.println("operation=" + operation);
            String operation2 = judgeRole03.judge(new OrderAdminRole("ROLE_ORDER_ADMIN"));
            System.out.println("operation2=" + operation2);
            String operation3 = judgeRole03.judge(new NormalRole("ROLE_NORMAL"));
            System.out.println("operation3=" + operation3);
        }
    
        //定义一个方法来调用RoleContext对象中获取角色权限的execute()方法
        public String judge(RoleOperation roleOperation) {
            RoleContext roleContext = new RoleContext(roleOperation);
            return roleContext.execute();
        }
    }
    
    

    以上就是几种常用的if else语句的优化方法,写代码前还是得多思考一番,考虑是否有更具可扩展性的写法!

    展开全文
  • 一个简单的if else优化

    千次阅读 2018-12-17 17:39:46
    优化优化后:

    优化前
    在这里插入图片描述

    优化后:
    在这里插入图片描述

    继续优化的话,可以将 24*60*60 存成一个常量。

    展开全文
  • 如何优化if else

    千次阅读 2019-12-17 01:36:56
    超过 3 层的 if-else 的逻辑判断代码可以使用卫语句、策略模式、状态模式等来实现。—— 阿里巴巴java开发手册 需求: 文件上传功能是一个常用的系统功能。那么上传后的文件保存到哪里呢?不同公司综合不同因素...

    超过 3 层的 if-else 的逻辑判断代码可以使用卫语句、策略模式、状态模式等来实现。—— 阿里巴巴java开发手册

    需求:

    文件上传功能是一个常用的系统功能。那么上传后的文件保存到哪里呢?不同公司综合不同因素,可能会打算把文件上传到不同的服务器中,比如:服务器本地,传输到 ftp 服务器,FastDFS 服务器,hdfs 服务器等。

    if else

    一般的话条件判断我们使用的是if else

    /**
     * if else 版本的上传文件代码
     */
    public class FileClient{
    
        private final static String LOCAL = "local";
        private final static String FTP = "ftp";
        private final static String FASTDFS = "fastdfs";
        private final static String HDFS = "hdfs";
    
    
        /**
         * 上传文件
         *
         * @param storageType 文件存储方式
         * @param file        文件
         */
        public void uploadFile(String storageType, String file) {
            if (storageType.equals(LOCAL)) {
                System.out.println("文件" + file + "已上传到 本地服务器");
            } else if (storageType.equals(FTP)) {
                System.out.println("文件" + file + "已上传到 ftp服务器");
            } else if (storageType.equals(FASTDFS)) {
                System.out.println("文件" + file + "已上传到 fastdfs服务器");
            } else if (storageType.equals(HDFS)) {
                System.out.println("文件" + file + "已上传到 hdfs服务器");
            } else {
                System.out.println("输入的文件存储类型错误");
            }
        }
        
        public static void main(String[] args) {
            FileClient fileClient = new FileClient();
            fileClient.uploadFile("hdfs","ifelse.txt");
        }
    }
    

    卫语句

    代码中大量的 if else 语句让人看着着实觉得眼花,并且在读代码的时候,容易自然地走完整段代码。因此出现了卫语句,用来简化一下代码查看时需要的处理量。

        /**
         * 上传文件
         *
         * @param storageType 文件存储方式
         * @param file        文件
         */
        public void uploadFileWithoutElse(String storageType, String file) {
            if (storageType.equals(LOCAL)) {
                System.out.println("文件" + file + "已上传到 本地服务器");
                return;
            } 
            if (storageType.equals(FTP)) {
                System.out.println("文件" + file + "已上传到 ftp服务器");
                return;
            } 
            if (storageType.equals(FASTDFS)) {
                System.out.println("文件" + file + "已上传到 fastdfs服务器");
                return;
            } 
            if (storageType.equals(HDFS)) {
                System.out.println("文件" + file + "已上传到 hdfs服务器");
                return;
            } 
            System.out.println("输入的文件存储类型错误");
        }
    

    去掉了 else 后,代码也变得比较有段落感,看起来更舒服了些。

    需求变更:给我加一个方式,上传到七牛云

    这里代码很简单,我们只需要增加 if 或者 if else 条件就好了,但是这样整个 FileUtils 文件的代码都会有改动,因此这个时候新的方法出现了。

    下面讲一下使用设计模式来减少 if else 的情况:

    简单工厂模式

    简单工厂模式属于创建型模式又叫做静态工厂方法模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。
    简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

    在这里插入图片描述

    这里我们把各个存储方式的上传行为给抽象出来:

    • 抽象
    	/**
    	 * 抽出各个方式共同的行为接口:上传文件
    	 */
    	public interface IStorageType {
    	    void uploadFile(String file);
    	}
    
    • 简单工厂(静态工厂)
    /**
     * 简单工厂
     */
    public class StorageTypeFactory {
    
        private final static String LOCAL = "local";
        private final static String FTP = "ftp";
        private final static String FASTDFS = "fastdfs";
        private final static String HDFS = "hdfs";
    
       public static IStorageType storageTypeCreate(String storageType) { 
            IStorageType iStorageType = null;
            switch (storageType) {
                case LOCAL:
                    iStorageType = new LocalStorageType();
                    break;
                case FTP:
                    iStorageType = new FtpStorageType();
                    break;
                case FASTDFS:
                    iStorageType = new FastDfsStorageType();
                    break;
                case HDFS:
                    iStorageType = new HdfsStorageType();
                    break;
            }
            return iStorageType;
        }
    
    }
    
    • 具体的上传方式( 以 hdfs 为例,其他类似)
    public class HdfsStorageType implements IStorageType {
        @Override
        public void uploadFile(String file) {
            System.out.println("文件" + file + "已上传到 hdfs服务器");
        }
    }
    
    • 客户端调用
    /**
     * 简单工厂模式 版本的上传文件代码
     */
    public class FileClient {
    
        public static void main(String[] args) {
            IStorageType iStorageType = StorageTypeFactory.storageTypeCreate("hdfs");
            iStorageType.uploadFile("simpleFactory.txt");
        }
    }
    
    

    回到场景中:这时候我们一旦要增加一个七牛云的存储方式,我们就可以直接在工厂里加一个 switch 条件,再加一个具体的七牛云存储行为即可。

    • 优点:
    1. 客户端可以在更改参数的条件下,不用变更其他代码,客户端不负责创建具体的存储方式,减少了对具体的存储方式的依赖,而是把这这件事交给了工厂。体现了职责单一原则。
    2. 当增加其他方式或者减少其他方式时,可以直接通过增加类以及 switch 条件,不会影响到具体的逻辑代码,修改较为简单。
    • 缺点
      这里违背了开闭原则,因为在对拓展开放时,对修改也进行了开放。(个人觉得耦合到的代码量并没有特别大,个人有时候还是会考虑以这样的方式进行修改代码)

    简单工厂模式适合的场景:
    1、判断分支数量不多,或者判断逻辑简单
    2、客户端只需记住参数,不用关系具体的实现细节

    参考文档:

    工厂模式–简单工厂模式

    策略模式

    在《大话设计模式》中对策略模式的解释是这样子的:它通过定义和封装算法,使得算法之间可以相互替换,让算法的变化不会影响到使用算法的用户。

    这句话理解起来有些拗口,我们先按照策略模式实现一下代码:

    • 策略
    	public abstract class StorageStrategy{
    	    public abstract void uploadFile(String file);
    	}
    
    • 具体策略
    public class FtpStorageStrategy extends StorageStrategy {
        @Override
        public void uploadFile(String file) {
            System.out.println("文件" + file + "已上传到 ftp服务器");
        }
    }
    
    • 策略上下文
    
    /**
     * 策略模式的上下文。
     */
    public class StorageContext {
    
        private StorageStrategy storageStrategy;
    
        public StorageContext(StorageStrategy storageStrategy) {
            this.storageStrategy = storageStrategy;
        }
    
        public void uploadFileAction(String file){
            storageStrategy.uploadFile(file);
        }
    }
    

    思考一:代理模式和策略模式的区别:

    上面的 StorageContext 感觉起来和代理模式中的代理有些像,那么这两者有什么区别呢?我上网搜了一下:
    (下面答案来自代理模式和策略模式的区别

    1. 简单代理模式中,代理类知道被代理类的行为,因为代理类与被代理类实现的是同一个接口,因此代理类与被代理类的结构是相同的
    2. 而策略模式中,策略容器并不知道内部策略的详细信息,因为容器并没有实现与内部策略相同的接口,
      即容器与内部策略只是简单的组合关系,容器只是将内部策略的行为抽取出来,进行了统一的实现。
    • 客户端调用
    
    /**
     * 策略模式 版本的上传文件代码
     */
    public class FileClient {
    
        private final static String LOCAL = "local";
        private final static String FTP = "ftp";
        private final static String FASTDFS = "fastdfs";
        private final static String HDFS = "hdfs";
    
        public static void main(String[] args) {
            StorageContext storageContext = null;
            //模拟入参
            String storageType = "ftp";
            switch (storageType) {
                case LOCAL:
                    //客户端需要知道具体有哪些策略,能做什么。但是不需要知道策略具体怎么做
                    storageContext = new StorageContext(new LocalStorageStrategy());
                    break;
                case FTP:
                    storageContext = new StorageContext(new FtpStorageStrategy());
                    break;
                case FASTDFS:
                    storageContext = new StorageContext(new FastDfsStorageStrategy());
                    break;
                case HDFS:
                    storageContext = new StorageContext(new HdfsStorageStrategy());
                    break;
            }
            storageContext.uploadFileAction("strategy.txt");
        }
    }
    

    这时候看刚刚的定义就比较好理解了:代码中的 StorageContext 实例就相当于是一个容器,客户端最终调用的是容器内部的行为(方法),至于这个行为要怎么实现,就结合不同情况使用不同的策略即可。

    思考二:在参数不变的情况下,if else 只是挪动了一个地方,感觉并没有很好的优化掉 if else 语句

    这里实际上是把 if else 的逻辑交给调用方(客户端)去处理了(用了switch),很不解,虽然说具体的策略解除了 if else ,但是调用方却要用到了。
    网上看到一些用 Map 来先预存好判断条件和策略的映射关系,觉得是治标不治本,因为这种方法我可以直接用 map 代替掉最原始的 if else 。
    看了下面这篇文章,依旧没有解除我的困惑。
    使用策略模式拯救满屏的 if-else

    个人觉得修改掉 if else 的话,输入参数不应该改变,也就是(String storageType, String file)。这两个作为客户端的输入参数。

    而网上现有的解决方案是:

    • 使用枚举
    • 使用 swich
    • 使用 Map

    不过每次一增加策略,就需要往上述的方法中增加条件。
    那能不能让我每次只加对应的策略,不加判断条件就可以直接使用新的策略呢?
    其实是可以的,下面将结合我们常用的 Spring 框架来看看如何进行操作?

    Spring中使用策略模式

    首先引入maven依赖,这里直接使用 springboot-web 的依赖(比较方便)

        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
        </dependencies>
    

    然后我们的策略接口要继承 Spring 的 InitializingBean 接口

    public interface IStorageType extends InitializingBean {
        void uploadFile(String file);
    }
    

    然后我们用一个单例模式来维护一下字符串与存储策略的对应关系:

    
    /**
     * 使用了饿汉式的单例模式
     */
    public class StorageMapSingleton {
    
        private HashMap<String, IStorageType> map = new HashMap<>();
    
        private static StorageMapSingleton storageMapSingleton = new StorageMapSingleton();
    
        private StorageMapSingleton(){
    
        }
    
        public static StorageMapSingleton getInstance(){
            return storageMapSingleton;
        }
    
        public IStorageType getStorageType(String type){
            return map.get(type);
        }
    
        /**
         * 这里使用默认的访问权限,允许在同一个package下面调用该方法。当前类必须和具体的实现类在同一个package下
         * @param type
         * @param storageType
         */
        void putStorageType(String type, IStorageType storageType){
            map.put(type, storageType);
        }
    
    }
    

    下面就是将具体的策略实现给注册并维护映射关系

    
    @Component
    public class FastDfsStorageType implements IStorageType {
    
       @Autowired
       private FastDfsStorageType fastDfsStorageType;
    
       private final static String LOCAL = "local";
    
       @Override
       public void uploadFile(String file) {
           System.out.println("文件" + file + "已上传到 fastdfs服务器");
       }
    
       /**
        * 当前 bean 被实例化后,会执行下面方法把字符串和策略的对应关系传进去
        */
       @Override
       public void afterPropertiesSet() {
           StorageMapSingleton.getInstance().putStorageType(LOCAL, fastDfsStorageType);
       }
    }
    

    下面我们建一个测试类来看一下是否能够正确运行:

    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = StorageApplication.class)
    public class StorageTypeTest {
    
    
        @Before
        public void testBefore(){
            System.out.println("测试前");
        }
    
        @After
        public void testAfter(){
            System.out.println("测试后");
        }
    
        @Test
        public void storageTest(){
            IStorageType iStorageType = StorageMapSingleton.getInstance().getStorageType("hdfs");
            iStorageType.uploadFile("策略模式.txt");
        }
    }
    

    控制台能够正常输出:文件策略模式.txt已上传到 本地服务器

    当我们加一个策略类:七牛云存储方式

    @Component
    public class QiniuStorageType implements IStorageType {
        @Autowired
        private QiniuStorageType qiniuStorageType;
    
        private final static String QINIU = "qiniu";
    
        
        @Override
        public void uploadFile(String file) {
            System.out.println("文件" + file + "已上传到七牛云");
    
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            StorageMapSingleton.getInstance().putStorageType(QINIU, qiniuStorageType);
        }
    }
    

    然后执行测试方法:

        @Test
        public void storageTest(){
            IStorageType iStorageType = StorageMapSingleton.getInstance().getStorageType("qiniu");
            iStorageType.uploadFile("策略模式.txt");
        }
    

    输出:文件策略模式.txt已上传到七牛云
    就可以达到只增加一个类,不用修改其他文件,就能够使用新的策略的目的

    小结:当前其实也是用了 Map 的映射关系来维护策略关系,但是通过单例模式和 Spring 的 InitializingBean 接口,避免了我们再去修改其他类。虽然代码复杂了一些,但是我们在对策略进行改动时,减少了改动的地方,也不用再去改动 if else 条件。
    PS:这里其实如果不依赖 Spring 的 InitializingBean 的话,还可以通过java 反射来达到维护 map 映射的效果。

    使用状态模式优化 if else

    《大话设计模式》中这样定义撞他器模式: 当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
    前面的上传文件的需求场景其实不适合用状态模式举例,因为上传文件方式基本不会用来作为一个状态。这里我们用一个菜鸟教程里的例子来举例 :

    打篮球的时候运动员可以有正常状态、不正常状态和超常状态。

    那这时候我们可以抽象各个状态下的统一行为:打篮球。

    /**
     * 抽象出统一行为
     */
    public interface State {
        void playBasketBall(Context context);
    }
    

    与策略模式很像,这里也有一个 Context 上下文

    /**
     * 其实相当于状态模式中的上下文Context
     */
    public class Boy {
        private State state;
    
        public Boy(){
            state = null;
        }
    
        public void setState(State state){
            this.state = state;
        }
    
        public void play(String action){
            state.doAction(action);
        }
    }
    

    具体状态下的行为(以正常状态下举例,其他两个状态类似)

    public class NormalState implements State {
    
        @Override
        public void doAction(String action) {
            System.out.println("正常发挥");
        }
    }
    
    

    客户端调用

    
    /**
     * 状态模式
     */
    
    /**
     * 状态模式
     */
    public class Client {
        public static void main(String[] args) {
            Boy boy = new Boy();
            State normal = new NormalState();
            boy.setState(normal);
            boy.play("打球");
    
            State unnormal = new UnnormalState();
            boy.setState(unnormal);
            boy.play("打球");
    
            State superNormal = new SupernormalState();
            boy.setState(superNormal);
            boy.play("打球");
        }
    }
    
    

    从这里可以看出,Boy 对象没有变化,其行为也没有变, 一直都是打球。但是由于 Boy 的状态变化了,所以同一行为有了不同的结果。正如我们生活中遇到一个人发挥超常或者发挥失常也会有这样一句描述:“他简直像换了一个人一样!”

    状态模式更侧重于行为对状态的依赖,这样客户端在调用对象的行为时,只需要关注其状态,只要确保行为会随着状态的变化而变化,那么调用时,就不用管行为是如何实现的。


    总结

    1、不要为了使用设计模式而去使用设计模式,代码的易读性更重要。在简单的条件判断下,用简单工厂模式,其实比使用策略模式容易理解的多,代码也是一看即明。
    2、策略模式更适合应对需求有一定的预见性,方便更好的组装策略与行为,侧重于要怎么做。
    3、状态模式更强调的是行为的主题,按照主体(上下文)状态的变化来觉得做什么。

    展开全文
  • 使用传统的if else扩展性不强,代码量越多阅读起来越困难 /** * 传统的If else 不容易扩展 代码量大的情况下代码阅读性不高 * @param args */ public static void main(String[] args) { Scanner scanner = ...
  • 利用Java8优化if else

    万次阅读 2022-05-16 14:06:42
    现在问题是if else 太多了,代码太长,项目不好维护和扩展,代码如下: public static String execute(String command, String jsonStr){ if ("openDoor".equals(command)) { // 具体业务代码会比较多,这里只是做...
  • if-else代码优化的八种方案

    千次阅读 2022-03-09 14:50:15
    目录 前言 优化方案一:提前return,去除不必要的else ...代码中如果if-else比较多,阅读起来比较困难,维护起来也比较困难,很容易出bug,接下来,本文将介绍优化if-else代码的八种方案。 优化方案一:
  • 优化IF-ELSE 代码结构的优化

    千次阅读 2021-07-10 19:25:05
    接下来,此文将介绍优化 if-else 代码的八种方案 2. 优化方案 方案一:提前 return,去除不必要的else 如果 if-else 代码块包含 return 语句,可以考虑通过提前 return,把多余 else 干掉,使代码更加优雅 优化前: ...
  • 【JAVA】优化if else的几种方式

    千次阅读 多人点赞 2020-04-01 17:05:56
    在代码编写初期,我们写出来的代码,脉络清晰,结构简单。...当我们狠下心来决定改造时,有哪些方法能够优化if else结构呢? 第一种方法:提前return,减少else判断 优化前: private int handlePre1(boolea...
  • if else 优化之策略模式

    千次阅读 2019-09-30 14:24:51
    if else 太多,嵌套太深,已然成为我们搬砖路上经常遇到的问题。最近在项目上使用策略模式,有助于优化嵌套的代码,使结构更加清晰。
  • 利用策略模式优化过多 if else 代码

    千次阅读 2020-11-30 10:56:47
    前言利用利用策略模式实际开发中 if else 条件判断过多的问题比如平时大家是否都会写类似这样的代码:if(a) {//dosomething}else if(b) {//doshomething}else if(c) {//doshomething}else{//doshomething}条件少还好...
  • vue if_else优化

    2020-11-10 14:27:35
    let map = { 100: “医生”, 200: “护士”, 300: “其他” }; this.workerType = map[this.$route.query.workerType]; if (this.$route.query.workerType == 100) { this.workerType = "医生";...} else if
  • 过多if-else分支的优化

    千次阅读 2020-11-30 10:56:52
    我想谈一谈这个话题是因为我的上一篇博客在ITEye上有一些朋友回复,说if-else过多的分支可以使用switch或者责任链模式等等方式来优化。确实,这是一个小问题,不过我们还是可以整理一下这个小问题的重构方式。为什么...
  • 像这种代码就很打脑壳~ // 贷款申请操作的处理 function check() { ... if (this.checkUsername(this.username)) { // 是否输入正确身份证号 if (this.checkIdCard(this.idCard)) { ... if (this.ch...
  • 优化 if-else 代码的 八 种方案

    千次阅读 2021-12-03 10:03:42
    不知各位是否有一种感觉,看到自己的写的代码中含有密密麻麻的if-else就很变扭。但是说这又是程序中不可或缺的点,也只能是强扭的瓜了。下面根据参考他人和自己理解的,列举出八种优化的写法,根据适合的场景使用...
  • 一、If语句If() { } If() {} else {} If() {} if() {} if() {} If() {} else if() {} else if() {} else {} 说明: 1) 可以进行嵌套,或者多重嵌套,但为保证代码逻辑清晰,提高可读性,尽量不要嵌套。 2) 按先后...
  • Java-记一次if-else代码优化

    万次阅读 多人点赞 2019-01-30 20:34:14
    文章目录概述原工程缩影第一次优化 【使用多态代替判断条件】Step1: 定义一个抽象的父类 AbstractFlowInfoExecutor ,抽取公共属性和方法Step2: 子类重写父类的方法,实现自定义业务逻辑Step3: 改造Service层Step3:...
  • java8 lambda表达式 if else 策略模式优化
  • C# 之 if-else代码优化

    千次阅读 2020-08-17 20:07:05
    C# 之 if-else代码优化; 方案一:提前return,去除不必要的else; 方案二:使用条件三目运算符; 方案三:使用Switch语句; 方案四:合并条件表达式; 方案五:真就是真,假就是假;
  • http://www.cnblogs.com/pfblog/p/7815238.html https://blog.csdn.net/u012475575/article/details/80969183
  • 多个if else如何优化

    万次阅读 2018-10-19 09:38:48
    这段时间一直在整改代码圈复杂度,我们的要求是每个函数方法圈复杂度不得大于5,以下是整改的部分截图 希望对整改代码的你有所提示或帮助,如果有更好的整改方法,还望您不吝赐教哦! ... ...
  • if-else嵌套过多时的优化方案

    千次阅读 2021-02-02 23:10:36
    //if-else嵌套过多时的优化方案在垒代码的时候经常会遇到 if-else 的嵌套判断,就是下一个判断依赖于上一个判断的结果,其基本的表现形式为if(){//first judgeif(){//second//do something}else{if(){//third//do ...
  • Java—优化 if-else 代码的 8 种方案

    千次阅读 2021-11-01 14:01:30
    代码中如果if-else比较多,阅读起来比较困难,维护起来也比较困难,很容易出bug,接下来,本文将介绍优化if-else代码的八种方案。 优化方案一:提前return,去除不必要的else 如果if-else代码块包含return语句,...
  • Java如何优化大量的if else

    万次阅读 多人点赞 2019-01-11 13:59:27
    业务代码中, if else 使用策略模式优化 设计模式 策略模式 极简策略模式 (妙用枚举) 责任链模式+策略模式 二、其他方案 1.分解条件表达式 if (date.before (SUMMER_START) || date.after(SUMMER_END)) { charge = ...
  • 如何对多个if-else判断进行优化

    万次阅读 2020-11-16 16:07:04
    当我们遇到需要多个条件判断的业务操作时,最简单直接的办法就是用多个if-else判断,虽然能够实现,但当判断条件过多,甚至是多元判断时,我们的代码就会变得非常不好阅读和维护。 举个例子 这里也可以用switch if...
  • Java优化:多个if else改用设计模式

    千次阅读 2021-04-30 14:41:17
    在实际项目中相信大家都遇到过令人糟心的代码,一个方法一溜下来全是if else,还写满了业务逻辑,代码如下: public static void main(String[] args) { String name = "张三"; if("张三".equals(name)){ // ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 577,271
精华内容 230,908
关键字:

ifelse优化