为什么需要设计模式?
因为项目的需求是不停的改变的,为了应对这些变化,让我们的代码能够很轻松的实现解耦和拓展。如果代码一旦写好以后再不需要任何改变,那你就可以按照你自己的想法随意写代码了。
如何判断哪里需要使用设计模式
工具类的代码写好以后基本上不会再改变了,一般也不会需要大的扩展了。但是有些代码是需要经常改变的,分析好代码会如何改变,然后选择合适的设计模式来优化这部分代码。
一个例子:
在电商行业中,有时候需要自定义促销:
比如有A、B、C、D四种类型的商品,
1、要求任意两种分类商品(A、B)一起买,打九折;
2、三种不同分类的商品(A、B、C)一起买,打八折;
3、四种不同分类的商品(A、B、C、D)一起买,打七折;
普通实现:
单独的看这个需求还是挺简单的,但是因为我们不可能一次就定义好以后需要所有类型的促销,在后续当中还需要根据实际情况自定义一些促销方式,这样代码写起来就比较困难了。
拿到需求我们可以直接上手:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class OrderPromotion { public BigDecimal promotion(Order order, int[] promotions){ for(int promotion:promotions){ switch (promotion){ case 1: break; case 2: break; case 3: break; } } return order.getResultPrice(); } }
|
从功能上来讲,上面的代码已经实现了需求,但是,实际使用起来还是很麻烦的,计算该类型折扣后的价格,单是这简单的一句注释就可能需要很多行代码才能实现。并且当我们后期需要一些新的促销活动时,需要在switch中添加需要的类型,这对于开发来说真的是太难了,并且后期维护这些代码也是巨大的麻烦。

优化:
一、单一职责原则:
在上面的代码当中,promotion()方法完成了所有的工作。在现实中,我们最好让一个方法只完成一个功能。所以,我们可以将上面代码中对折扣类型的判断和计算折扣价格两个功能分开完成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public class OrderPromotion { public BigDecimal promotion(Order order, int[] promotions){ for(int promotion:promotions){ switch (promotion){ case 1: calculate1(order); break; case 2: calculate2(order); break; case 3: calculate3(order); break; } } return order.getResultPrice(); }
public void calculate1(Order order){ }
public void calculate2(Order order){ }
public void calculate3(Order order){ } }
|
这样,promotion()方法中的代码就会少很多了,整个代码的可读性会大大加强。
二、策略模式:
策略模式的主要思想是定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。策略模式的最大特点是使得算法可以在不影响客户端的情况下发生变化,从而改变不同的功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class OrderPromotion { public BigDecimal promotion(Order order, int[] promotions){ for(int promotion:promotions){ switch (promotion){ case 1: new PromotionType1Calculate(order); break; case 2: new PromotionType1Calculate(order); break; case 3: new PromotionType1Calculate(order); break; } } return order.getResultPrice(); } }
|
通过策略模式,我们只需要在有新的促销方式时,定义一个新的促销类,实现PromotionType1Calculate()后,在switch中添加即可。
三、工厂模式:
经过前两步的优化,代码已经简单许多了。但是在每次添加新的促销方式时,OrderPromotion还是需要变化的。那么我们就可以使用工厂模式将PromotionType1Calculate的实例化分离开。
1 2 3 4 5 6 7 8
| public class OrderPromotion { public BigDecimal promotion(Order order, int[] promotions){ for(int promotion:promotions){ PromotionFactory.getPromotionCalculate(promotion).calculate(order); } return order.getResultPrice(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class PromotionFactory { public static PromotionCalculate getPromotionCalculate(int promotion){ switch (promotion){ case 1: return new PromotionType1Calculate(order); break; case 2: return new PromotionType1Calculate(order); break; case 3: return new PromotionType1Calculate(order); break; } return null; } }
|
这样,OrderPromotion就不需要再改变了,后期只需要在PromotionFactory中添加需要的促销方式即可。
最后的代码实际上还有不足,每次添加新的促销方式的时候还需要修改PromotionFactory工厂类,我们还可以通过一些方法做更进一步的优化,这次就不在记述了。
