使用设计模式改写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 }
处理类:
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 }
调用:
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语句今天就写到这,大家有兴趣的可以在评论区回复交流。