标签:
任务:或在公司,该公司将其分为三类人员:部门经理、销售员。在发工资的时候,部门经理拿固定月薪8000元。技术人员按每小时100元领取月薪。销售人员依照500元底薪加当月销售额的4%进行提成。设计并实现一个工资结算系统。
分析:无论是部门经理、技术员还是销售员都具有员工的共同特征。能够先设计一个员工类(Employee)。并将结算工资的方法设计为抽象方法,由于不同的员工有不同的结算工资的方式,须要进行多态实现。所谓的抽象方法就是没有方法体并被abstract修饰符修饰的方法。假设一个类中有抽象方法,这个类就要被声明为抽象类。抽象类不能实例化,也就是说不能创建抽象类的对象。接下来能够在员工类的基础上派生出经理类(Manager)、技术员类(Technician)和销售员类(Salesman),这三个类要对员工类中的抽象方法进行重写(override),给出自己的结算工资的方法的实现,这个过程称为继承(inheritance),这是面向对象程序设计的三大支柱之中的一个。接下来,在须要进行工资结算时。能够将全部的员工对象都赋值给Employee类型的引用(由于无论是部门经理、技术员还是销售员都是员工,父类型的引用能够引用子类型的对象,这是上转型不须要强制的类型转换)。再用相同的引用调用相同的结算工资的方法。这样相同的引用调用相同的方法却做了不同的事(每种员工结算工资的方式全然不一样),这就是面向对象最精髓的东西——多态(polymorphism),它和封装(encapsulation)、继承一起构成了面向对象的三大支柱。
以下是该系统的UML类图。
UML(Unified Modeling Language)称为统一建模语言,。UML是一种开放的方法,用于说明、可视化、构建和编写一个正在开发的、面向对象的、软件密集系统的制品的开发方法。UML展现了一系列最佳project实践,这些最佳实践在对大规模。复杂系统进行建模方面,特别是在软件架构层次已经被验证有效。
简单的说,UML是一种图形化的语言,提供了绘制软件project图纸的标准符号。
上面的图是UML中的类图,它描写叙述了系统中的类以及类与类之间的关系,当中空心的三角型箭头表示继承关系。类与类之间的关系除了继承(IS-A关系)外,还有关联(HAS-A关系)和依赖(USE-A关系)。
该系统的代码例如以下所看到的:
Employee.java
package com.lovo.salsys; /** * 员工类 * @author 骆昊 */ public abstract class Employee { private String name; // 姓名 /** * 构造器 * @param name 员工姓名 */ public Employee(String name) { this.name = name; } /** * 结算工资 * @return 当月月薪 */ public abstract double getSalary(); /** * 获得员工姓名 * @return 姓名 */ public String getName() { return name; } @Override public String toString() { return name; } }
package com.lovo.salsys; /** * 部门经理类 * @author 骆昊 */ public class Manager extends Employee { public Manager(String name) { super(name); } public double getSalary() { return 8000.0; } public String toString() { return "[部门经理]" + super.toString(); } }
package com.lovo.salsys; /** * 技术工类 * @author 骆昊 */ public class Technician extends Employee { private int workingHour; // 工作时间 public Technician(String name) { super(name); } public void setWorkingHour(int workingHour) { this.workingHour = workingHour; } public double getSalary() { return 100 * workingHour; } public String toString() { return "[技 术 工]" + super.toString(); } }
package com.lovo.salsys; /** * 销售员类 * @author 骆昊 */ public class Salesman extends Employee { private double sales; // 销售额 public Salesman(String name) { super(name); } public void setSales(double sales) { this.sales = sales; } public double getSalary() { return 500 + sales * 0.04; } public String toString() { return "[销 售 员]" + super.toString(); } }
package com.lovo.salsys; import java.util.Scanner; class SalarySystemRunner { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String[] names = {"张飞", "关羽", "马超", "黄忠", "赵云"}; Employee[] emps = new Employee[names.length]; for(int i = 0; i < emps.length; i++) { int empType = (int) (Math.random() * 3); switch(empType) { case 0: emps[i] = new Manager(names[i]); break; case 1: emps[i] = new Technician(names[i]); break; case 2: emps[i] = new Salesman(names[i]); break; } System.out.println(emps[i]); } for(Employee e : emps) { if(e instanceof Technician) { System.out.print("请输入" + e.getName() + "的本月工作时间: "); ((Technician) e).setWorkingHour(sc.nextInt()); } else if(e instanceof Salesman) { System.out.print("请输入" + e.getName() + "的本月销售额: "); ((Salesman) e).setSales(sc.nextDouble()); } System.out.println(e.getName() + "本月工资为: $" + e.getSalary()); } sc.close(); } }
实现多态有两个关键点:方法重写(子类在继承过程中重写父类方法)和对象造型(将子类对象赋值给父类引用)。这里事实上涉及到了面向对象程序设计两个很重要的原则。一是依赖倒转原则(Dependency Inversion Principle),二是里氏代换原则(Liskov Substitution Principal)。依赖倒转原则讲的是要面向接口编程,而不要面向实现编程。详细的说就是,当定义方法的參数类型、方法的返回类型、对象的引用类型时,有抽象类型尽可能使用抽象类型。上面的样例中,我们将各种不同类型的员工对象对装在Employee类型的数组中就是将对象的引用类型定义为抽象类型。里氏代换原则讲的是不论什么时候都能够用子类对象替换父类对象。也就是说能使用父类型的地方就一定能使用子类型。这样假设一个方法的參数是父类型对象。传入它的不论什么一个子类型都没有问题。假设子类对父类中的方法给出了不同的实现的版本号。那在用父类型的引用调用该方法时就会表现出多态行为。相同的道理,假设一个方法的返回类型是父类型。则在方法中能够返回该父类型的不论什么一个子类型对象,这种话我们在创建对象的时候能够编写一个工厂方法,从而从创建出不同的子类对象,这就是GoF静态设计模式工厂模式。让我们来解释一下在下一章这种设计通过实例。
版权声明:本文博客原创文章,博客,未经同意,不得转载。
[连载]Java程序设计(04)---任务驱动的方法:工资结算系统
标签:
原文地址:http://www.cnblogs.com/mengfanrong/p/4733685.html