Avoid excessive if - else the new position: Wei statements, small functions, polymorphism, reflection

table of Contents

 

Foreword

Wei statement

Code:

Small function

Demeter

concept:

Code:

Map extracting objects

Stream

Polymorphism

reflection


Foreword

In our normal development process, due to time constraints the project, code can be used like, tend to ignore the quality of the code. Some even copied and pasted over, do not collate specification. Often leads to late project difficult to maintain, let alone follow-up to people to take over the project. So, ah, we have to write elegant code, allowing you and me, not Miya?

I share some common coding in the development of the following 小建议, if wrong, we welcome the exchange of learning together.

Wei statement

Wei statement is to complex conditional expressions into multiple conditional expressions. For example a plurality of if-elseif-elsenested, can be split into a plurality if. The code below

Code:


-------------------- before  --------------------

public void today() {
    if (isWeekend()) {
        if (isFee()) {
            System.out.println("study Android");
        } else {
            System.out.println("play a game");
        }
    } else {
        System.out.println("go to work");
    }
}


 -------------------- after  (建议) --------------------

public void today() {

    // 提前过滤掉`特殊情况`
    if (!isWeekend()) {
        System.out.println("go to work");
        return; // 提前return
    }

    //提前过滤掉`特殊情况`
    if (isFee()) {
        System.out.println("study Android");
        return; // 提前return
    }

    // 更关注于 `核心业务`代码实现。
    System.out.println("play a game");
}

Filter out ahead of 特殊the situation, we are more concerned about 核心business logic

Small function

We normally developed, you should write 小而美a function to avoid 函数过长. General function best in 15 lines or less ( 建议) We look at the code below:


-------------------- before  --------------------

if (age > 0 && age < 18){
    System.out.println("小孩子");
}

if (number.length() == 11){
    System.out.println("符合手机号");
}

-------------------- after (建议) --------------------

private static boolean isChild(int age) {
    return age > 0 && age < 18;
}

private static boolean isPhoneNumber(String number) {
    return number.length() == 11;
}

if (isChild(age)){
    System.out.println("小孩子");
}

if (isPhoneNumber(number)){
    System.out.println("符合手机号");
}

Analyzing the sentence extracted into one 小函数, so that the code more clear.

Demeter

concept:

Demeter (Law of Demeter) also called the principle of least knowledge (Least Knowledge Principle abbreviation LKP), that is to say an object should do to other objects 可能少of 了解. For example, when an object appears in a statement two .( student.getName().equals("张三")) is the code bad taste performance, as shown in the following code.

Code:


-------------------- before  --------------------

public class Student {

    private String name;

    public Student(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

public static void main(String[] args) {

    Student student = new Student("张三");

    // 注意看这里,
    // 这里获取 student的name属性,在根据name属性进行判断
    if (StringUtils.isNotBlank(student.getName()) && student.getName().equals("张三")) {
        System.out.println("我的好朋友是 " + student.getName());
    }
}


 -------------------- after (建议) --------------------
 
 public class Student {

    ... 省略name代码

    // 新增一个 判断是否是我的好朋友方法
    public boolean isGoodFriend(){
        return StringUtils.isNotBlank(this.name) && this.name.equals("张三");
    }
}

public static void main(String[] args) {

    Student student = new Student("张三");

    // 根据迪米特法则,把判断逻辑,抽取到 Student 内部,暴露出方法(isGoodFriend)
    if (student.isGoodFriend()){
        System.out.println("我的好朋友是 " + student.getName());
    }
}

IDEA / Android Studio extraction method Shortcuts: option + command + M

Map extracting objects

We usually development, will be used to map, but in object-oriented development philosophy, one mapuse, they tend to miss Java Bean. Recommended Java Beanmore intuitive. The following code:

public static void main(String[] args) {

    -------------------- before  --------------------
        Map<String, String> studentMap = new HashMap<>();
        studentMap.put("张三", "男");
        studentMap.put("小红", "女");
        studentMap.put("李四", "男");

        studentMap.forEach((name, sex) -> {
            System.out.println(name + " : " + sex);
        });

    -------------------- after (建议)  --------------------
    
        List<Student> students = new ArrayList<>();
        students.add(new Student("张三", "男"));
        students.add(new Student("小红", "女"));
        students.add(new Student("李四", "男"));

        for (Student student : students) {
            System.out.println(student.getName() + ":" + student.getSex());
        }
    }

I write this point in time, we have concerns. There must be a small partner out of it, mapand beannot the same? Use mapalso eliminates the need to think about how I named Classit. But from the code specification, this type of code design is not more in line with Java 面向对象the idea of it?

Stream

Java 8 API adds a new abstraction called stream Streamthat allows you to process the data in a declarative way. Making it more elegant code to call - direct look at the code:

public static void main(String[] args) {
        List<Student> students = new ArrayList<>();
        students.add(new Student("张三", "男"));
        students.add(new Student("李四", "男"));
        students.add(new Student("小红", "女"));
        students.add(new Student("小花", "女"));
        students.add(new Student("小红", "女"));
        
        -------------------- before  --------------------
        //统计男生个数
        //传统的 for each 循环遍历
        long boyCount = 0;
        for (Student student : students) {
            if (student.isBoy()) {
                boyCount++;
            }
        }

        System.out.println("男生个数 = " + boyCount);

        -------------------- after (建议)  --------------------

        //统计男生个数
        //stream 流遍历
        long count = students.stream()
                .filter(Student::isBoy) // 等同于.filter(student -> student.isBoy())
                .count();
                
        System.out.println("男生个数 = " + boyCount);
}

Compared with the traditional Forcycle, but we recommend using streamtraversal. streamChain call flow, show many operations, such as sorted, map, collectand other operators, unnecessary may be omitted if-else, countand other decision logic.

Polymorphism

One of the three characteristics of the Java, 多态, I believe we are not unfamiliar, it is to take advantage of multi-state behavior of different types depending on the subject. We often write switchthe time statement, if the switch to multi-state, each branch can be extracted to overwrite function within a subclass, which is more flexible.

We have such a need to write a simple calculator method, we first look at a snippet of code:


    -------------------- before  --------------------
    public static int getResult(int numberA, int numberB, String operate) {
        int result = 0;
        switch (operate) {
            case "+":
                result = numberA + numberB;
                break;
            case "-":
                result = numberA - numberB;
                break;
            case "*":
                result = numberA * numberB;
                break;
            case "/":
                result = numberA / numberB;
                break;
        }
        return result;
    }
    
    -------------------- after (建议)  --------------------
    
    abstract class Operate {
        abstract int compute(int numberA, int numberB);
    }
    
    class AddOperate extends Operate {

        @Override
        int compute(int numberA, int numberB) {
            // TODO 在这里处理相关逻辑
            return numberA + numberB;
        }
    }
    
    ... SubOperate, MulOperate, DivOperate 也和 AddOperate一样这里就不一一贴出
    
    public static int getResult(int numberA, int numberB, String operate) {
        int result = 0;
        switch (operate) {
            case "+":
                result = new AddOperate().compute(numberA, numberB);
                break;
            case "-":
                result = new SubOperate().compute(numberA, numberB);
                break;
            case "*":
                result = new MulOperate().compute(numberA, numberB);
                break;
            case "/":
                result = new DivOperate().compute(numberA, numberB);
                break;
        }
        return result;
    }

A small partner might say, you is not more complicated yet?

Compared to the simple switch, we can interpret it this way:

  • Although an increase in the class, but by the polymorphism, separating out the logic operation corresponding to such code is the degree of coupling is reduced.
  • If you want to modify the corresponding 加法logic, we only need to modify the corresponding AddOperateclass on it. Avoid direct modification getResultmethod
  • The code more readable, semantic clearer.

But there will be some problems, if we add a new 平方根, 平方and so calculation, you need to modify the switchinside of logic, add a conditional branch. Here we look at further optimization.

reflection

By way of example above, we can further optimize, by 反射generating a corresponding Class, then call computemethod. The following code:

public static <T extends Operate> int getResult(int numberA, int numberB, Class<T> clz) {
        int result = 0;
        try {
            return clz.newInstance().compute(numberA, numberB);
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
            return result;
        }
}


public static void main(String[] args) {
    // 调用的时候直接传递 class 即可
    System.out.println(getResult(1, 2, SumOpearte.class));
}

The passed classparameters, and then generates a corresponding Opearteprocessing class, polymorphically contrast, here we are reflective, so that the code coupled greatly reduced, if increased 平方根, 平方and so calculated. We only need to add a classsuccession Opeartecan, getResultwithout any changes.

It should be noted that not all switchstatements need to replace, in the face of a simple switchstatement is unnecessary, avoiding 过度设计the suspect. The following code:

public String getResult(int typeCode) {
        String type = "";
        switch (typeCode) {
            case 0:
                type = "加法";
                break;
            case 1:
                type = "减法";
                break;
            case 2:
                type = "乘法";
                break;
            case 3:
                type = "触发";
                break;
        }
        return type;
}


Link: https: //juejin.im/post/5dafbc02e51d4524a0060bdd
 

Published 393 original articles · won praise 1149 · Views 1.66 million +

Guess you like

Origin blog.csdn.net/fly910905/article/details/104090150