一。场景
以前给医院算过一次医院工作人员的工资每种医生护士的工资算法都不同,当时特别蠢,直接面向过程,频繁的ifelse去计算。
最近可能会计算律师的工资,所以自己编一个律师工资为场景。实际上的工资计算远远要麻烦的多
1.律师有实习律师、正式律师、律师主任三种类型
2.实习律师的工资为基本工资1000+所办案件收入的10%+出勤数*100;
正式律师的工资为基本工资2000+所办案件收入的20%+出勤数*200
主任的工资为基本工资3000+所办案件收入的30%+出勤数*300
二。实现
1.简单工厂的实现:
https://blog.csdn.net/u014203449/article/details/83020398
2.策略模式
算法接口
public interface SalaryCalculation {
/**
*
* @param workDays 出勤数
* @param baseSalayr基本工资
* @param caseAmount 案件收费金额
* @param lawyerType 律师类型
* @return
*/
public Double getSalary(Double baseSalary,Integer workDays,Double caseAmount,Integer lawyerType);
}
各律师算法的实现
public class Director implements SalaryCalculation {
@Override
public Double getSalary(Double baseSalary, Integer workDays, Double caseAmount, Integer lawyerType) {
return baseSalary+workDays*300+caseAmount*0.3;
}
}
public class LawyerSalayr implements SalaryCalculation {
@Override
public Double getSalary(Double baseSalayr, Integer workDays, Double caseAmount, Integer lawyerType) {
return baseSalayr+workDays*200+caseAmount*0.2;
}
}
public class LawyerSalayr implements SalaryCalculation {
@Override
public Double getSalary(Double baseSalayr, Integer workDays, Double caseAmount, Integer lawyerType) {
return baseSalayr+workDays*200+caseAmount*0.2;
}
}
SalaryContext,用来维护一个SalaryCalculation的引用
public class SalaryContext {
//维护一个SalaryCalculation对象
SalaryCalculation salaryCalculation;
//得到工资的方法就用维护的对象
public Double getSalary(Double baseSalary,Integer workDays,Double caseAmount,Integer lawyerType) {
return salaryCalculation.getSalary(baseSalary, workDays, caseAmount, lawyerType);
}
public SalaryCalculation getSalaryCalculation() {
return salaryCalculation;
}
public void setSalaryCalculation(SalaryCalculation salaryCalculation) {
this.salaryCalculation = salaryCalculation;
}
public SalaryContext(SalaryCalculation salaryCalculation) {
super();
this.salaryCalculation = salaryCalculation;
}
}
客户端:
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.print("请输入律师类型");
String lawyerType = scan.nextLine();
System.out.print("请输入基本工资");
String baseSalary = scan.nextLine();
System.out.print("请输入出勤数");
String workDays = scan.nextLine();
System.out.print("请输入案件金额");
String caseAmount = scan.nextLine();
switch (lawyerType) {
case "1":
SalaryContext SalaryContext = new SalaryContext(new InternshipSalary());
System.out.println(SalaryContext.getSalary(Double.valueOf(baseSalary), Integer.valueOf(workDays), Double.valueOf(caseAmount), Integer.valueOf(lawyerType));
break;
case "2":
SalaryContext SalaryContext1 = new SalaryContext(new LawyerSalayr());
System.out.println(SalaryContext1.getSalary(Double.valueOf(baseSalary), Integer.valueOf(workDays), Double.valueOf(caseAmount), Integer.valueOf(lawyerType));
break;
case "3":
SalaryContext SalaryContext2 = new SalaryContext(new Director());
System.out.println(SalaryContext2.getSalary(Double.valueOf(baseSalary), Integer.valueOf(workDays), Double.valueOf(caseAmount), Integer.valueOf(lawyerType));
break;
}
}
缺点:这样又回到了最初客户端暴露出switch了,在客户端判断用哪种算法
3.策略模式和简单工厂结合
修改 SalaryContext,简单工厂不一定非要是一个类,利用简单工厂创建不同类型对象的特点
public class SalaryContext {
//维护一个SalaryCalculation对象
SalaryCalculation salaryCalculation;
//得到工资的方法就用维护的对象
public Double getSalary(Double baseSalary,Integer workDays,Double caseAmount,Integer lawyerType) {
return salaryCalculation.getSalary(baseSalary, workDays, caseAmount, lawyerType);
}
public SalaryContext(Integer lawyerType) {
switch (lawyerType) {
case 1:
salaryCalculation = new InternshipSalary();
break;
case 2:
salaryCalculation = new LawyerSalayr();
break;
case 3:
salaryCalculation = new Director();
break;
}
}
}
客户端
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.print("请输入律师类型");
String lawyerType = scan.nextLine();
System.out.print("请输入基本工资");
String baseSalary = scan.nextLine();
System.out.print("请输入出勤数");
String workDays = scan.nextLine();
System.out.print("请输入案件金额");
String caseAmount = scan.nextLine();
SalaryContext SalaryContext = new SalaryContext(Integer.valueOf(lawyerType));
Double salary = SalaryContext.getSalary(Double.valueOf(baseSalary), Integer.valueOf(workDays), Double.valueOf(caseAmount), Integer.valueOf(lawyerType));
System.out.println(salary);
比较简单工厂和策略模式
简单工厂
SalaryCalculation calculation = SalaryFactory.createSalaryCalculation(Integer.valueOf(lawyerType));
Double salary = calculation.getSalary(Double.valueOf(baseSalary), Integer.valueOf(workDays), Double.valueOf(caseAmount), Integer.valueOf(lawyerType));
System.out.println(salary);
简单工厂在客户端暴露了两个类,工厂类和算法接口,策略模式只暴露出了SalaryContext,使工资算法彻底与客户端分离
可是始终有switch,只要律师类型增加,就得修改SalaryContext,怎么办?
4.与反射结合
修改SalaryContext,用反射创建对象,参数是类的地址,输入的lawyerType不再是数字,而是类名,与定义的packageName结合起来正好创建对象
这个例子可能不太好,但表达的意思是,不需要switch改动代码,直接通过一个字符串变量去创建对象。免去修改代码的麻烦
public class SalaryContext {
//维护一个SalaryCalculation对象
SalaryCalculation salaryCalculation;
String packageName = "SimpleFactory";
//得到工资的方法就用维护的对象
public Double getSalary(Double baseSalary,Integer workDays,Double caseAmount) {
return salaryCalculation.getSalary(baseSalary, workDays, caseAmount);
}
public SalaryContext(String lawyerType) {
try {
salaryCalculation =(SalaryCalculation) Class.forName(packageName+"."+lawyerType).newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
三。点睛
1.策略模式封装了算法,封装了一系列规则,在开发中,发现不同情况会采用不同的业务规则,就可以考虑使用
2.面向对象封装,避免直接ifelse switch,客户端最外层判断使用哪种算法
3.减少了使用算法类和算法类间的耦合
4.最初判断使用的职责在客户端,运用简单工厂,转移到了SalaryContext上,再运用反射可避免switch的修改