继承和组合的联系(策略模式--组装车间):计算不同身份员工工资案例
公司有三类人员,新入职人员,中层人员和领导,三种身份的工资计算是不同的,先看一下简单的结构图。。。
用继承来实现的话:
abstract class Employee{
int id;
double salary;
public abstract void setCalcSalary(int id,double salary);
public double CalculatSalary() {
// TODO Auto-generated method stub
System.out.println(id);
return salary;
}
}
class JuniorEmployee extends Employee{
@Override
public void setCalcSalary(int id,double salary) {
// TODO Auto-generated method stub
this.id=id;
this.salary=salary;
}
}
class SeniorEmployee extends Employee{
@Override
public void setCalcSalary(int id, double salary) {
// TODO Auto-generated method stub
this.id=id;
this.salary=salary+500;
}
}
class ManagerEmployee extends Employee{
@Override
public void setCalcSalary(int id, double salary) {
// TODO Auto-generated method stub
this.id=id;
this.salary=salary+1000;
}
}
public class Test4 {
public static void main(String[] args) {
JuniorEmployee j=new JuniorEmployee();//id=1的员工入职了
j.setCalcSalary(1, 3000);
System.out.println(j.CalculatSalary());
SeniorEmployee s=new SeniorEmployee();//id=1的员工晋升了
s.setCalcSalary(1, 5000);
System.out.println(s.CalculatSalary());
ManagerEmployee m=new ManagerEmployee();//id=1的员工晋升了
m.setCalcSalary(1, 8000);
System.out.println(m.CalculatSalary());
}
}
上面的继承代码你会发现,虽然是一个员工,但是创建了3个对象,还必须要保证三个id必须相同。先不说这样妥不妥,单单对象创建就消耗了不必要的资源。用组合的方法更简便:
interface ICalculateSalary {
double calculateSalary(double baseSalary);
}
class JuniorEmployee implements ICalculateSalary{
public double calculateSalary(double baseSalary) {
return baseSalary;
}
}
class SeniorEmployee implements ICalculateSalary{
public double calculateSalary(double baseSalary) {
return baseSalary+500;
}
}
class ManagerEmployee implements ICalculateSalary{
public double calculateSalary(double baseSalary) {
return baseSalary+1000;
}
}
class Employee{
int id;
double baseSalary;
ICalculateSalary employee;
Employee(int id){
this.id=id;
}
void setCalcSalary(ICalculateSalary employee,double baseSalary) {
this.employee=employee;
this.id=id;
System.out.println(id+":"+employee.calculateSalary(baseSalary));
}
}
public class Test4 {
public static void main(String[] args) {
Employee e=new Employee(1);
e.setCalcSalary(new JuniorEmployee(),3000);
e.setCalcSalary(new SeniorEmployee(),5000);
e.setCalcSalary(new ManagerEmployee(), 6000);
}
}
在组合模式下,只创建了一个对象,把晋升的身份当成参数传入了,而且可以动态在不同的策略下切换身份,非常灵活,这就是组合。
细心的读者可能会疑问,继承需要一个父类3个子类,组合需要一个接口3个子类,加1个雇员类,反而复杂了,没必要。
下面我们归纳一下继承和组合的优缺点:
继承是is a关系,可以翻译成 我是一个xxx。
组合是has a关系,可以翻译成 我有一个xxx。
就单单看字面意思,我有比我是强多了。(举个例子,A说我是一个妹子,B说我有一个妹子。。。。那A就只能是个妹子,B的话有一个妹子可能还有其他妹子。)
继承的优点:
子类可以重写父类的方法来实现对父类的扩展。
继承的缺点:
1.父类的内部细节子类可见
2.子类从父类继承的方法在编译时就确定下来了,无法再运行期间改变父类的方法。
3.如果对父类做了修改的话,必须对子类的方法做出相应的修改,所以这里就体现了高耦合(你会发现你的工作成了ctrl+c和ctrl+v。这样会浪费你大部分工作时间,很繁琐)
组合的优点:
1.当前对象(Employee)只能通过所包含的那个对象(ICalculateSalary的实例)去调用其方法,所包含的对象内部细节对当前对象是不可见的。
2.当前对象(Employee)与包含的对象(ICalculateSalary的实例)是一个低耦合关系,如果修改包含的类中的代码不需要修改当前对象的代码。
3.当前对象(Employee)在运行时动态绑定所包含的对象(多态),可以通过set方法对包含对象赋值(这个例子我用一个成员变量赋值了)
组合的缺点:
1.容易产生过多对象(这里我不理解)
2.为了能组合多个对象,必须仔细对接口进行定义。
组合是实现策略模式的关键,但策略模式照样需要继承的支持,但主题架构依然是组合,继承是发生在分叉中的故事。