【敏捷软件开发 原则、模式与实践】第 18 到 19 章笔记

薪水支付案例

规格说明

用户素材

  • 增加新雇员
  • 删除雇员
  • 登记时间卡
  • 登记销售凭条
  • 登记协会服务费
  • 更改雇员明细
  • 运行薪水支付系统

员工类型

  • 钟点工

    按小时计算薪水,每天正常工作 8 小时,超过 8 小时部分 1.5 倍薪水,每周五支付薪水。

  • 销售雇员

    有固定月薪,同时根据销售业绩有相应的酬金,每隔一周的周五支付薪水。

  • 普通雇员

    固定月薪,每月最后一天支付薪水。

薪水支付方式

  • 将支票邮寄到指定地址
  • 在出纳人员那儿领取支票
  • 将薪水存入员工制定的银行账户

补充说明

  • 员工如果加入一些公司的协会,每月会从薪水中扣除协会的服务费
  • 薪水支付程序每个工作日运行一次,并在当天为相应的雇员进行支付。系统会被告知雇员的支付日期,这样它会计算从雇员是国内次支付日期到规定的本次支付日期间应支付的数额

基础类设计

支付方式

public interface PaymentMethod {}

public class HoldMethod implements PaymentMethod {}

public class DirectMethod implements PaymentMethod {
    private String bank;
    private String account;
}

public class MailMethod implements PaymentMethod {
    private String address;
}

支付类型

public interface PaymentClassification {}

public class SalariedClassification implements PaymentClassification {
    private Integer salary;
}

public class HourlyClassification implements PaymentClassification {
    private Integer hourlyRate;
}

public class CommissionedClassification implements PaymentClassification {
    private Integer commissionRate;
    private Intger salary;
}

员工

public class Emplyee {
    private String name;
    private Integer employeeId;
    private String address;

    public Emplyee(String name, Integer employeeId, String address) {
        this.name = name;
        this.employeeId = employeeId;
        this.address = address;
    }

    // setter/getter
}

public class HourlyEmployee extends Emplyee {
    private Integer hourlyRate;
}

public class SalariedEmployee extends Emplyee {
    private Integer monthlySalary;
}

public class CommissionedEmployee extends Emplyee {
    private Integer monthlySalary;
    private Integer commissionRate;
}

薪水支付时间表

public interface PaymentSchedule {}

public class WeeklySchedule implements PaymentSchedule {}

public class MonthlySchedule implements PaymentSchedule {}

public class BiweeklySchedule implements PaymentSchedule {}

时间卡

public class TimeCard {
    private Date date;
    private Integer hours;
}

销售凭条

public class SalesReceipt {
    private Date date;
    private Integer amount;
}

服务费用

public class ServiceCharge {
    private Date date;
    private Integer amount;
}

雇员与协会关系类

public interface Affiliation {

}

public class NoAffiliation implements Affiliation {

}

public class UnionAffiliation implements Affiliation {
    
}

数据库

使用 facade 模式

public class PayrollDatabase {
    private Map<Integer, Emplyee> itsEmployee;

    public PayrollDatabase() {
        itsEmployee = new HashMap<>();
    }

    public Emplyee getEmployee(Integer empId) {
        return itsEmployee.get(empId);
    }

    public void addEmployee(Emplyee employee, Integer empId) {
        itsEmployee.put(empId, employee);
    }

    public void clear() {}
}

用例分析

采用测试驱动开发的方式实现每一个模块

所有操作的抽象基类

使用 command 模式

public interface Transaction {
    void execute();
}

增加雇员

  • 增加雇员基础类结构

使用 template method 模式

public abstract AddEmployeeTransaction implements Transaction {
    private Integer empId;
    private String address;
    private String name;
    private PayrollDatabase payrollDatabase;

    public abstract void execute() {}

    // setter/getter
}

public class AddHourlyEmployee extends AddEmployeeTransaction {
    private Integer hourlyRate;
    public void execute() {}
}

public class AddSalariedEmployee extends AddEmployeeTransaction {
    private Integer salary;
    public void execute() {}
}

public class AddCommissionedEmployee extends AddEmployeeTransaction {
    private Integer salary;
    private Integer commissionRate;
    public void execute() {}
}
  • 测试用例
    • 增加固定月薪类型雇员
      public void testAddSalariedEmployee {
         // 1. 创建固定月薪类型员工
         // 2. 通过员工 id 从数据库中查询员工,对结果进行断言
         // 3. 从员工对象获取员工的支付类型,对结果进行断言
         // 4. 从员工对象获取支付时间表,对结果进行断言
         // 5. 从员工对象获取支付方式,对结果进行断言
      }
      
    • 增加销售类型雇员
      public void testAddCommissionedEmployee {
        // 1. 创建销售类型雇员
        // 2. 通过员工 id 从数据库中查询员工,对结果进行断言
        // 3. 从员工对象获取员工的支付类型,对结果进行断言
        // 4. 从员工对象获取支付时间表,对结果进行断言
        // 5. 从员工对象获取支付方式,对结果进行断言
      }
      
    • 增加钟点类型雇员
      public void testAddHourlyEmployee {
        // 1. 创建固钟点类型员工
        // 2. 通过员工 id 从数据库中查询员工,对结果进行断言
        // 3. 从员工对象获取员工的支付类型,对结果进行断言
        // 4. 从员工对象获取支付时间表,对结果进行断言
        // 5. 从员工对象获取支付方式,对结果进行断言
      }
      

删除雇员

  • 测试用例
    public void testDeleteEmployee {
        // 1. 创建一个雇员
        // 2. 通过 id 从数据库中获取雇员,并对结果进行断言
        // 3. 通过 ID 从数据库中删除雇员
        // 4. 通过 ID 从数据库中获取雇员,并对结果进行断言
    }
    

给钟点类型雇员添加时间卡

  • 时间卡操作类

    public class TimeCardTransaction implements Transaction {
        private Date date;
        private Integer hours;
        private Integer empId;
        private PayrollDatabase payrollDatabase;
      
        public void execute();
    }
    
  • 测试用例

    public void testTimeCard {
      // 1. 创建一个雇员
      // 2. 创建一个 TimeCardTransaction 对象,并执行 execute 方法
      // 3. 通过 id 从数据库中获取雇员对象,并对结果断言
      // 4. 从雇员对象中获取钟点支付类型,并对结果进行断言
      // 5. 从钟点支付类型中获取时间卡,并对结果进行断言
    }
    

给销售类型雇员添加销售凭条

  • 销售凭条操作类

    public class SalesReceiptTransaction implements Transaction {
        private Date date;
        private Integer amount;
        private Integer empId;
        private PayrollDatabase payrollDatabase;
    
        public void execute();
    }
    
  • 测试用例

    public void testSalesReceipt {
        // 1. 创建一个雇员
        // 2. 创建一个 SalesReceiptTransaction 对象,并执行 execute 方法
        // 3. 通过 id 从数据库中获取雇员对象,并对结果断言
        // 4. 从雇员对象中获取销售雇员支付类型,并对结果进行断言
        // 5. 从钟点支付类型中获取销售凭条,并对结果进行断言
    }
    

向协会成员登记服务费

  • 操作类

    public class ServiceChargeTransaction implements Transaction {
        private Date date;
        private Integer amount;
        private Integer memberID;
        private PayrollDatabase payrollDatabase;
    
        public void execute();
    }
    
  • 测试用例

    public void testServiceCharge {
        // 1. 创建一个雇员
        // 2. 根据 ID 从数据库中获取雇员对象,并对结果进行断言
        // 3. 创建一个 UnionAffiliation 对象,并 set 雇员对象中
        // 4. 在数据库中新增一个会员
        // 5. 创建一个 ServiceChargeTransaction 对象
        // 6. 从 UnionAffiliation 对象中获取 ServiceCharge 对象,并对结果进行断言
    }
    

更改雇员属性

  • 操作类

    使用 template method 模式

    public abstract ChangeEmployeeTransaction implements Transaction {
        private PayrollDatabase payrollDatabase;
        private Emplyee employee;
        private Integer empId;
    
        public abstract void execute();
    }
    
    public class ChangeNameTransaction extends ChangeEmployeeTransaction {
        private String name;
    
        public void execute();
    }
    
    public class ChangeAddressTransaction extends ChangeEmployeeTransaction {
        private String address;
    
        public void execute();
    }
    
    
    public abstract ChangeClassificationTransaction extends ChangeEmployeeTransaction {
        private PaymentClassification paymentClassification;
        private PaymentSchedule paymentSchedule;
    
        public abstract void execute();
    }
    
    public class ChangeHourlyTransaction extends ChangeClassificationTransaction {
        private Integer hourlyRate;
    
        public void execute();
    }
    
    public class ChangeSalariedTransaction extends ChangeClassificationTransaction {
        private Integer salary;
    
        public void execute();
    }
    
    public class ChangeCommissionedTransaction extends ChangeClassificationTransaction {
        private Integer salary;
        private Integer commissionRate;
    
        public void execute();
    }
    
    
    public abstract ChangeMethodTransaction extends ChangeEmployeeTransaction {
        private PaymentMethod paymentMethod;
    
        public abstract void execute();
    }
    
    public class ChangeDirectTransaction extends ChangeMethodTransaction {
        private String account;
        private String bank;
    
        public void execute();
    }
    
    public class ChangeHoldTransaction extends ChangeMethodTransaction {
        public void execute();
    }
    
    public class ChangeMailTransaction extends ChangeMethodTransaction {
        private String address;
    
        public void execute();
    }
    
    
    public abstract ChangeAffiliationTransaction extends ChangeEmployeeTransaction {
        private Affiliation affiliation;
    
        public abstract void execute();
    }
    
    public class ChangeMemberTransaction extends ChangeAffiliationTransaction {
        public void execute();
    }
    
    public class ChangeUnaffiliatedransaction extends     ChangeAffiliationTransaction {
          public void execute();
    }
    
  • 测试用例

    • 更改名字
      public void testChangeNameTransaction {
        //1. 创建一个雇员对象
        //2. 创建一个 ChangeNameTransaction 对象,并执行 execute 方法
        //3. 通过 id 从数据库中获取雇员对象,并对结果进行断言
      }
      
    • 更改雇员地址
      public void testChangeAddressTransaction {
       //1. 创建一个雇员对象
       //2. 创建一个 ChangeNameTransaction 对象,并执行 execute 方法
       //3. 通过 id 从数据库中获取雇员对象,并对结果进行断言
      }
      
    • 更改雇员类型
      public void testChangeHourlyTransaction {
        //1. 新增一个雇员对象
        //2. 创建一个 ChangeNameTransaction 对象,并执行 execute 方法
        //3. 通过 id 从数据库中获取雇员对象,并对结果进行断言
        //4. 从雇员对象中获取 PaymentClassification 对象,并对结果进行断言
        //5. 从 PaymentClassification 对象中获取 PaymentSchedule 对象,并对结果进行断言
      }
      
    • 更改薪水支付方式
      public void testChangeMethodTransaction {
        //1. 新增一个雇员对象
        //2. 创建一个 ChangeMethodTransaction 对象,并执行 execute 方法
        //3. 通过 id 从数据库中获取雇员对象,并对结果进行断言
        //4. 从雇员对象中获取 PaymentMethod 对象,并对结果进行断言
      }
      
    • 更改雇员与协会关联
      public void testChangeMemberTransaction {
        //1. 新增一个雇员对象
        //2. 创建一个 ChangeMemberTransaction 对象,并执行 execute 方法
        //3. 通过 id 从数据库中获取雇员对象,并对结果进行断言
        //4. 从雇员对象中获取 UnionAffiliation 对象,并对结果进行断言
        //5. 根据 memberID 从数据库中获取雇员对象,并对结果进行断言
      }
      

支付雇员薪水

  • 支付固定月薪雇员薪水
    public void testPaySingleSalariedEmployee() {
      //1. 创建一个雇员对象
      //2. 创建一个支付日期
      //3. 验证日期是否是发薪日
      //4. 断言支付方式
      //5. 断言支付金额
    }
    
    public void testPaySingleSalariedEmployeeOneWrongDate() {
      //1. 创建一个雇员对象
      //2. 创建一个支付日期
      //3. 验证日期是否是发薪日
    }
    
  • 支付钟点雇员薪水
     public void testPaySingleHourlyEmployeeNoTimeCards() {
       //1. 创建一个雇员对象
       //2. 创建一个支付日期
       //3. 验证日期是否是发薪日
       //4. 断言支付方式
       //5. 断言支付金额
     }
    
     public void testPaySingleHourlyEmployeeOneTimeCards() {
       //1. 创建一个雇员对象
       //2. 创建一个支付日期
       //3. 验证日期是否是发薪日
       //4. 断言支付方式
       //5. 断言支付金额
     }
    
     public void testPaySingleHourlyEmployeeOneWrongDate() {
       //1. 创建一个雇员对象
       //2. 创建一个支付日期
       //3. 验证日期是否是发薪日
     }
    
     public void testPaySingleHourlyEmployeeTwoTimeCards() {
       //1. 创建一个雇员对象
       //2. 创建一个支付日期
       //3. 验证日期是否是发薪日
       //4. 断言支付方式
       //5. 断言支付金额
     }
    
     public void testPaySingleHourlyEmployeeWithTimeCardsSpanningTwoPayPeriods() {
       //1. 创建一个雇员对象
       //2. 创建一个支付日期
       //3. 验证日期是否是发薪日
       //4. 断言支付方式
       //5. 断言支付金额
     }  
    
  • 支付带有销售酬金的雇员薪水
    public void testPaySingleCommissionedEmployee() {
        //1. 创建一个雇员对象
        //2. 创建一个支付日期
        //3. 验证日期是否是发薪日
        //4. 断言支付方式
        //5. 断言支付金额
      }
    

计算会费和服务费测试用例

public void testSalariedUnionMemberDues() {}

public void testHourlyUnionMemberServiceCharge() {}

public void testServiceSpanningMultiplePayPeriods() {}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容