[Unlock new posture] recall the fear of being dominated by `if-else`, we have to overthrow if - else

Foreword

[Unlock new posture] brother dei, you need to optimize the code
before the article said, simply if-else, can be used 卫语句for optimization. But in the actual development, often not a simple if-elsestructure, we usually 不经意间write the following code:


-------------------- 理想中的 if-else  --------------------
public void today() {
    if (isWeekend()) {
        System.out.println("玩游戏");
    } else {
        System.out.println("上班!");
    }
}


-------------------- 现实中的 if-else  --------------------

if (money >= 1000) {
    if (type == UserType.SILVER_VIP.getCode()) {

        System.out.println("白银会员 优惠50元");
        result = money - 50;
    } else if (type == UserType.GOLD_VIP.getCode()) {

        System.out.println("黄金会员 8折");
        result = money * 0.8;
    } else if (type == UserType.PLATINUM_VIP.getCode()) {

        System.out.println("白金会员 优惠50元,再打7折");
        result = (money - 50) * 0.7;
    } else {
        System.out.println("普通会员 不打折");
        result = money;
    }
}


//省略 n 个 if-else ......

复制代码

It is no exaggeration to say that we have written similar code, recalling the if-elsefear dominated, we often start with nothing, or even nothing.

Here to share my experience in the development of complex if-elsestatements “优雅处理”ideas. If wrong, we welcome the exchange of learning together.

demand

Suppose there is such a demand:

A electricity supplier system, when a user consumption 满1000amounts, based on user VIP level, receive a discount.

VIP levels based on the user to calculate the cost of the final user.

  • Ordinary members do not discount
  • Silver membership benefits 50 yuan
  • Gold 20%
  • Platinum membership benefits 50, 30% off resort

Coding

private static double getResult(long money, int type) {

    double result = money;

    if (money >= 1000) {
        if (type == UserType.SILVER_VIP.getCode()) {

            System.out.println("白银会员 优惠50元");
            result = money - 50;
        } else if (type == UserType.GOLD_VIP.getCode()) {

            System.out.println("黄金会员 8折");
            result = money * 0.8;
        } else if (type == UserType.PLATINUM_VIP.getCode()) {

            System.out.println("白金会员 优惠50元,再打7折");
            result = (money - 50) * 0.7;
        } else {
            System.out.println("普通会员 不打折");
            result = money;
        }
    }

    return result;
}
复制代码

To facilitate the presentation, the code I realized a simple, but in fact if - elsewill be 复杂的逻辑charged. Functionally, the basic completion, but for people like me have the code over the top of it, could not bear to look directly on the code quality. We started 优化at our 第一版代码bar.

Think

See above codes, smart friends first thought is that this is not typical of 策略模式it?

You're a smart boy, we explore the use of strategy mode to optimize the code it.

Strategy Mode

What is the strategy pattern?

Some friends still unclear, what is the strategy pattern. Strategy pattern is to define a series of algorithms, put them one 封装up, and make them mutually 替换.

For example, the above demand, 返利there 打折, there 折上折, and so on. The algorithm itself is a kind 策略. And each of these algorithms can 替换, for example today I want to 白银会员优惠50, tomorrow can be replaced 白银会员打9折.

He said so much, it is better coding more real.

coding

public interface Strategy {
    
    // 计费方法
    double compute(long money);
}

// 普通会员策略
public class OrdinaryStrategy implements Strategy {

    @Override
    public double compute(long money) {
        System.out.println("普通会员 不打折");
        return money;
    }
}

// 白银会员策略
public class SilverStrategy implements Strategy {

    @Override
    public double compute(long money) {

        System.out.println("白银会员 优惠50元");
        return money - 50;
    }
}

// 黄金会员策略
public class GoldStrategy implements Strategy{

    @Override
    public double compute(long money) {
        System.out.println("黄金会员 8折");
        return money * 0.8;
    }
}

// 白金会员策略
public class PlatinumStrategy implements Strategy {
    @Override
    public double compute(long money) {
        System.out.println("白金会员 优惠50元,再打7折");
        return (money - 50) * 0.7;
    }
}
复制代码

We come to a definition of Strategythe interface, and defines four sub-classes that implement the interface. In a corresponding computerealization method of accounting policy logic itself.

private static double getResult(long money, int type) {

    double result = money;

    if (money >= 1000) {
        if (type == UserType.SILVER_VIP.getCode()) {

            result = new SilverStrategy().compute(money);
        } else if (type == UserType.GOLD_VIP.getCode()) {

            result = new GoldStrategy().compute(money);
        } else if (type == UserType.PLATINUM_VIP.getCode()) {

            result = new PlatinumStrategy().compute(money);
        } else {
            result = new OrdinaryStrategy().compute(money);
        }
    }

    return result;
}
复制代码

Then the corresponding getResultmethod, according to typereplace the corresponding user the VIP 策略. Here there have been repeated calls on the code compute, we can try to be further optimized.

private static double getResult(long money, int type) {

    if (money < 1000) {
        return money;
    }

    Strategy strategy;

    if (type == UserType.SILVER_VIP.getCode()) {
        strategy = new SilverStrategy();
    } else if (type == UserType.GOLD_VIP.getCode()) {
        strategy = new GoldStrategy();
    } else if (type == UserType.PLATINUM_VIP.getCode()) {
        strategy = new PlatinumStrategy();
    } else {
        strategy = new OrdinaryStrategy();
    }

    return strategy.compute(money);
}
复制代码

I still remember the first article comes in 卫语句it? We are here to put money <1000 case of early return. More focused on 满1000逻辑, you can also reduce unnecessary indentation.

Ponder

I once thought that the strategy pattern better than this. Code optimization thought to this already.

But there is a terrible thing, if-elsestill exists :)

I try to read a lot of books, to see how to eliminate policy mode if-else

Most of the methods in the book is to use simple tactics + factory mode. The if - elseswitch to switchcreate a factory method only.

But this is far from what I want to achieve the effect, Down if - else

Until one day night, my big brother a share in the group Java8when the tips, from wide open a new world.

Factory + Strategy

public interface Strategy {

    double compute(long money);

    // 返回 type
    int getType();
}


public class OrdinaryStrategy implements Strategy {

    @Override
    public double compute(long money) {
        System.out.println("普通会员 不打折");
        return money;
    }

    // 添加 type 返回
    @Override
    public int getType() {
        return UserType.SILVER_VIP.getCode();
    }
}

public class SilverStrategy implements Strategy {

    @Override
    public double compute(long money) {

        System.out.println("白银会员 优惠50元");
        return money - 50;
    }

    // type 返回
    @Override
    public int getType() {
        return UserType.SILVER_VIP.getCode();
    }
}

....省略剩下 Strategy
复制代码

We first in a new Strategy getTypemethod for 标示the policy typevalue. Code is relatively simple, there is not too much description of

public class StrategyFactory {

    private Map<Integer, Strategy> map;

    public StrategyFactory() {

        List<Strategy> strategies = new ArrayList<>();

        strategies.add(new OrdinaryStrategy());
        strategies.add(new SilverStrategy());
        strategies.add(new GoldStrategy());
        strategies.add(new PlatinumStrategy());
        strategies.add(new PlatinumStrategy());

        // 看这里 看这里 看这里!
        map = strategies.stream().collect(Collectors.toMap(Strategy::getType, strategy -> strategy));
        
        /* 等同上面
        map = new HashMap<>();
        for (Strategy strategy : strategies) {
            map.put(strategy.getType(), strategy);
        }*/
    }

    public static class Holder {
        public static StrategyFactory instance = new StrategyFactory();
    }

    public static StrategyFactory getInstance() {
        return Holder.instance;
    }

    public Strategy get(Integer type) {
        return map.get(type);
    }
}
复制代码

Kind of static internal singleton class, single embodiment mode of realization, this article is not the focus, if not understood, it can be self google

We then set out to create a StrategyFactoryfactory class. StrategyFactory here I am using 静态内部类单例, when a constructor to initialize that you need Strategy, and put listinto map. Here is the transformation “灵魂”lies.

toMap

Let's take a look at Java8the grammar tips.

Under normal circumstances, we traverse the List, Manual putto Map.

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

map = new HashMap<>();
for (Strategy strategy : strategies) {
    map.put(strategy.getType(), strategy);
}

--------------  after Java8 -----------------

map = strategies.stream().collect(Collectors.toMap(Strategy::getType, strategy -> strategy));
复制代码

toMapThe first parameter is a Function, corresponding to the Map key, the second parameter is a Function, strategy -> strategy, on the left strategyis a traversal strategies each Strategy, the right strategyis the corresponding Map valuevalue.

Do not know if Java8friends grammar, it is strongly recommended to see " Java8 实战," the book describes in detail the Lambdaexpression, Streamsuch as grammar.

effect

private static double getResult(long money, int type) {

    if (money < 1000) {
        return money;
    }

    Strategy strategy = StrategyFactory.getInstance().get(type);
    
    if (strategy == null){
        throw new IllegalArgumentException("please input right type");
    }

    return strategy.compute(money);
}
复制代码

So far, through a factory class, in our getResult()time of the call, based on the incoming type, you can get to the correspondingStrategy

No terrible if-elsestatement.

Sahua Sahua end:)

Follow-up

The subsequent code optimization, if Java project, you can try 自定义注解, annotations Strategy implementation class.

This simplifies the original need to add a factory class List Stratey 策略.

At last

That is all I encountered in the development of complex if-elsestatements “优雅处理”ideas, if wrong, we welcome the exchange of learning together.

Guess you like

Origin juejin.im/post/5def654f51882512302daeef