使用设计模式改写if/else或switch/case语句

在写代码的时候,经常会用到if/else语句或者switch/case语句。虽然很省事,但是没有体现到java的封装、继承、多态等特性。没有用到java的面向对象编程的精髓。

比如这种if/else语句:

String str = "菠萝";
if ("苹果".equals(str)) {
	System.out.println("又大又红的苹果");
}
else if ("菠萝".equals(str)) {
	System.out.println("又酸又甜的菠萝");
}
else if ("梨".equals(str)) {
	System.out.println("又甜又脆的梨");
}

我们应该如何使用设计模式改写呢?

第一种方式:使用策略模式

接口:Strategy

public interface Strategy {
    void comment();
}

苹果实现类:

public class Apple implements Strategy {
    @Override
    public void comment() {
        System.out.println("又大又红的苹果");
    }
}

菠萝实现类:

public class Pineapple implements Strategy {
@Override
public void comment() {
System.out.println("又酸又甜的菠萝");
}
}

 梨实现类:

public class Pear implements Strategy {
    @Override
    public void comment() {
        System.out.println("又甜又脆的梨");
    }
}

枚举类:

1 public enum FruitsEnum {
2     APPLE, PINEAPPLE, PEAR;
3 }
View Code

处理类:

 1 public class People {
 2     private static Map<FruitsEnum, Strategy> map;
 3 
 4     static {
 5         map = new HashMap();
 6         map.put(FruitsEnum.APPLE, new Apple());
 7         map.put(FruitsEnum.PINEAPPLE, new Pineapple());
 8         map.put(FruitsEnum.PEAR, new Pear());
 9     }
10 
11     public static void commentFruit(FruitsEnum fruitEnum) {
12         for (Map.Entry<FruitsEnum, Strategy> entry : map.entrySet()) {
13             if (fruitEnum.equals(entry.getKey())) {
14                 entry.getValue().comment();
15             }
16         }
17     }
18 }
View Code

调用:

People.commentFruit(FruitsEnum.PINEAPPLE);

策略模式(Strategy Pattern)属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。
其主要目的是通过定义相似的算法,替换if else 语句写法,并且可以随时相互替换。
策略模式主要由这三个角色组成,环境角色(Context)、抽象策略角色(Strategy)和具体策略角色(ConcreteStrategy)。

环境角色(Context):持有一个策略类的引用,提供给客户端使用。
抽象策略角色(Strategy):这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
具体策略角色(ConcreteStrategy):包装了相关的算法或行为。
示例图如下:

相比传统的if/else语句,使用策略模式后代码体现出了面向对象的特性,扩展性更强,但是还是存在一些缺陷,需要一个map,而且需要new出每个实现类的实例。学过spring的都知道这样存在非常强的耦合性,这个时候可以用到spring ioc相关的知识点来改写。

第二种方式:策略模式+spring ioc(ApplicationObjectSupport)

接口:Strategy

public interface Strategy {
    void comment();
}

苹果实现类:

@Component
public class Apple implements Strategy {
    @Override
    public void comment() {
        System.out.println("又大又红的苹果");
    }
}

菠萝实现类:

@Component
public class Pineapple implements Strategy {
    @Override
    public void comment() {
        System.out.println("又酸又甜的菠萝");
    }
}

梨实现类:

@Component
public class Pear implements Strategy {
    @Override
    public void comment() {
        System.out.println("又甜又脆的梨");
    }
}

枚举类:

public enum FruitEnum {
    APPLE("苹果", "apple"), PINEAPPLE("菠萝", "pineapple"), PEAR("梨", "pear");

    private String name;
    private String desc;

    FruitEnum(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }

    public String getName() {
        return name;
    }

    public String getDesc() {
        return desc;
    }

    public static FruitEnum find(String type) {
        FruitEnum fruitEnum = Arrays.stream(FruitEnum.values()).filter(f -> type.equals(f.getName()))
                .findFirst().orElse(null);
        return fruitEnum;
    }
}

继承ApplicationObjectSupport:

@Service
public class PeopleStrategyService extends ApplicationObjectSupport {
    public Strategy getInstance(String type) {
        return super.getApplicationContext().getBean(FruitEnum.find(type).getDesc(), Strategy.class);
    }
}

处理类:

@Service
public class PeopleService {
    @Autowired
    private PeopleStrategyService peopleStrategyService;

    public void peopleComment(String type) {
        peopleStrategyService.getInstance(type).comment();
    }
}

调用:

peopleService.peopleComment(FruitEnum.PINEAPPLE.getName());

这里主要用到策略模式和spring ioc相关的知识点。

1.ApplicationObjectSupport的知识点

2.@Component、@Service、@Autowired等注解的知识点

这种方式发挥了spring ioc的优点,解决了耦合性,但还不是最简洁的方式。

第三种方式:策略模式+spring ioc(InitializingBean)

接口:继承InitializingBean

public interface EventService extends InitializingBean {
    void handler();
}

苹果实现类:

@Service
public class AppleEventServiceImpl implements EventService {
    @Override
    public void handler() {
        System.out.println("又大又红的苹果");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        EventServiceFactory.register(FruitEnum.APPLE.getName(), this);
    }
}

菠萝实现类:

@Service
public class PineappleEventServiceImpl implements EventService {
    @Override
    public void handler() {
        System.out.println("又酸又甜的菠萝");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        EventServiceFactory.register(FruitEnum.PINEAPPLE.getName(), this);
    }
}

这里省略掉梨的实现类,大家可以自己去补充

枚举类也省略,大家自己去补充

处理类:

@Component
public class EventServiceFactory {
    private static Map<String, EventService> EVENT_SERVICE_MAP = new ConcurrentHashMap<>();

    public static EventService getHandler(String type) {
        return EVENT_SERVICE_MAP.get(type);
    }

    public static void register(String type, EventService eventService) {
        EVENT_SERVICE_MAP.put(type, eventService);
    }
}

调用:

EventServiceFactory.getHandler(FruitEnum.APPLE.getName()).handler();

这里主要用到策略模式和spring ioc相关的知识点。

1.InitializingBean(afterPropertiesSet)的知识点

这种方式是我能想到的最简洁的方式了,同时解决了耦合性的问题。

当然也可以省略掉枚举类,switch/case的场景用枚举比较多,if/else的情况下可以不用枚举类,把变量放在对应的实现类里面即可。

好的,使用设计模式改写if/else或switch/case语句今天就写到这,大家有兴趣的可以在评论区回复交流。

posted @ 2023-09-16 15:39  Aaronqcd  阅读(95)  评论(0编辑  收藏  举报