版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ddxxii/article/details/78012701
事例
一个每天打饭的时候,都会打一个荤菜和一个素菜和一人饭。饭固定,一个人一块,素菜也是固定的,只要1.6元而荤菜则根据不同菜品和不同重量来计算。鸭肉需要1.5块一两,鸡肉需要2块一两,猪肉1.8块一两。换算到java中,我们要计算中午饭多少钱,可以用如下方式。
public class PriceClient{
private static int pork=1;
private static int chicken=2;
private static int dock=3;
public static void main(String[] args){
PriceClient priceClient=new PriceClient();
System.out.println("今天吃米饭+素菜+3两猪肉,价格是:"+priceClient.calcuatePrice(pork,3));
}
/**
* 计算价格
* @param liang 两数
*/
float calcuatePrice(int type , int liang){
float price=1+1.6;//先计算出米饭和素菜的价格
if(pork==type){
return price+porkPrice(liang);
}else if(chicken==type){
return price+chickenPrice(liang);
}else{
return price+dockPrice(liang);
}
}
/**
* 猪肉1.8一两
* @param liang 两数
*/
private float porkPrice(int liang){
return 1.8*liang;
}
/**
* 鸡肉2一两
* @param liang 两数
*/
private float chickenPrice(int liang){
return 2*liang;
}
/**
* 鸭肉1.5一两
* @param liang 两数
*/
private float dockPrice(int liang){
return 1.5*liang;
}
}
现在这代码看起来还是挺简单的吧,而且还是对每个肉类的价格是分开在不同方法内计算的了,看起来简单吗?但是如果肉类品种越来越多,那又得不断在后面加if-else来判断返回具体执行方法。然后这个类中的代码越来越臃肿,难以维护。另外增加的时候,可能很多时候是通过复制粘贴的方式,手动复制很容易引入错误。
就这里就违反了我们说的,开关闭原则,每次要增加都在这个类中修改。也违反了单一原则,一个类包含了多个计算方式。
在这里我们可以利用抽象来解决这个问题。
抽象实现
- UML图
- 创建一个接口,来定义价格计算方法:
/**
* 价格策略计算接口
*/
public interface StragetyPrice {
/**
*
*/
public void calcuatePrice();
}
- 实际计算类
/**
* 猪肉计算
*/
public class ConcerateStragetyPork implements Stragety {
/**
* Default constructor
*/
public ConcerateStragetyPork() {
}
/**
* 计算价格
*/
public float calcuatePrice(int liang) {
return 1.8*liang;
}
}
/**
* 鸡肉计算
*/
public class ConcerateStragetyChicken implements Stragety {
/**
* Default constructor
*/
public ConcerateStragetyChicken() {
}
/**
* 计算价格
*/
public float calcuatePrice(int liang) {
return 2*liang;
}
}
/**
* 鸭肉计算
*/
public class ConcerateStragetyDock implements Stragety {
/**
* Default constructor
*/
public ConcerateStragetyDock() {
}
/**
* 计算价格
*/
public float calcuatePrice(int liang) {
return 1.5*liang;
}
}
- Client修改:
public class PriceClient{
private Stragety stragety;
public static void main(String[] args){
PriceClient priceClient=new PriceClient();
priceClient.setStragety(new ConcerateStragetyDock());//设置猪肉
System.out.println("今天吃米饭+素菜+3两猪肉,价格是:"+priceClient.calcuatePrice(3));
}
public void setStragety(Stragety stragety){
this.stragety=stragety;
}
/**
* 计算价格
* @param liang 两数
*/
float calcuatePrice(int liang){
float price=1+1.6;//先计算出米饭和素菜的价格
return price+stragety.calcuatePrice(liang);
}
}
这个样子来实现可变的部分,然后达到可扩展的效果,如果后面还有另外的荤菜,只需要加入一个实现Stragety接口就可以了。对之前的代码修改关闭,也体现了调用client的单一职责,它只需要调用和设置,真正的可变计算在各自实现类中。
总结
基本的简单实现到这里就结束了。策略模式也是一个使用很多的设计模式,优点在于替换if-else结构,在一个整体流程中,如果因为其中某一部分可变造成结果可变的不妨就使用策略模式。如果是全部都可变可替换,你还是可以考虑工厂模式,所以说所有设计模式都大同小异呢,但是使用场景和站的角度不同你就可以看成是不同的设计模式。最终结果是为了更优雅的实现方式即六大原则。