当前位置: 首页 > news >正文

网站的构思wordpress 伪静态 .htaccess

网站的构思,wordpress 伪静态 .htaccess,做网站框架,四川网站建设 湖南岚鸿回顾薪资管理系统的设计建模 在 3-15 课#xff0c;我们通过场景驱动设计完成了薪资管理系统的领域设计建模。既然场景驱动设计可以很好地与测试驱动开发融合在一起#xff0c;因此根据场景驱动设计的成果来开展测试驱动开发#xff0c;就是一个水到渠成的过程。让我们先来…回顾薪资管理系统的设计建模 在 3-15 课我们通过场景驱动设计完成了薪资管理系统的领域设计建模。既然场景驱动设计可以很好地与测试驱动开发融合在一起因此根据场景驱动设计的成果来开展测试驱动开发就是一个水到渠成的过程。让我们先来看看针对薪资管理系统“支付薪资”领域场景分解的任务 确定是否支付日期 确定是否为周五确定是否为月末工作日 获取当月的假期信息确定当月的最后一个工作日确定是否为间隔一周周五 获取上一次销售人员的支付日期确定是否间隔了一周计算雇员薪资 计算钟点工薪资 获取钟点工雇员与工作时间卡根据雇员日薪计算薪资计算月薪雇员薪资 获取月薪雇员与考勤记录对月薪雇员计算月薪计算销售人员薪资 获取销售雇员与销售凭条根据酬金规则计算薪资支付 向满足条件的雇员账户发起转账生成支付凭条 根据任务分解驱动出来的时序图完整脚本则如下所示 PaymentAppService.pay() {PaymentService.pay() {PayDayService.isPayday(today) {Calendar.isFriday(today);WorkdayService.isLastWorkday(today) {HolidayRepository.ofMonth(month);Calendar.isLastWorkday(holidays);} WorkdayService.isIntervalFriday(today) {PaymentRepository.lastPayday(today);Calendar.isFriday(today);}}PayrollCalculator.calculate(employees) {HourlyEmployeePayrollCalculator.calculate() {HourlyEmployeeRepository.all();while (employee - ListHourlyEmployee) {employee.payroll(PayPeriod);}}SalariedEmployeePayrollCalculator.calculate() {SalariedEmployeeRepository.all();while (employee - ListSalariedEmployee) {employee.payroll();}}CommissionedEmployeePayrollCalculator.calculate() {CommissionedEmployeeRepository.all();while (employee - ListCommissionedEmployee) {employee.payroll(payPeriod);}}}PayingPayrollService.execute(employees) {TransferClient.transfer(account);PaymentRepository.add(payment);}} } 测试驱动的方向 有了分解的任务也有了履行职责的各个角色构造型现在是万事俱备只欠东风。让我们严格按照测试驱动开发的红绿黄节奏以及三定律开展领域实现建模。首先我们要选择需要添加测试的新功能。场景驱动设计在分解任务时是从外部代表业务价值的领域场景逐步向内推进和拆分的这是一个从外向内的驱动设计方向测试驱动开发则不同为了尽可能避免编写需要模拟的单元测试应该从内部代表业务实现的原子任务开始先完成细粒度的自给自足的领域行为逻辑单元然后逐步往外推进直到完成满足完整领域场景的所有任务这是一个从内向外的驱动开发方向 这就意味着在开始测试驱动开发之前我们需要选择合适的任务。需要考虑的因素包括 任务的依赖性任务的重要性 从依赖的角度看并不一定需要优先选择前序任务因为我们可以使用模拟的方式驱动出当前任务需要依赖的接口而无需考虑实现。不过基于场景驱动开发分解的任务层次为其编写测试用例时也应优先挑选无需访问外部资源的原子任务即为聚合编写单元测试因为它无需任何模拟行为。至于任务的重要性主要是判断任务是否整个系统或模块的核心功能。在确定了领域场景的前提下一个判断标准是确定任务是主要流程还是异常流程。通常而言应优先考虑任务的主流程。 显然支付薪资领域场景的核心功能是支付与薪资计算。由于支付由外部服务完成剩下要实现的核心功能就是薪资计算。如果从原子任务开始挑选应首先从内部的原子任务开始挑选例如选择“根据雇员日薪计算薪资”原子任务 计算雇员薪资 计算钟点工薪资 获取钟点工雇员与工作时间卡根据雇员日薪计算薪资计算月薪雇员薪资 获取月薪雇员与考勤记录对月薪雇员计算月薪计算销售人员薪资 获取销售雇员与销售凭条根据酬金规则计算薪资 测试驱动开发的过程 编写失败的测试 现在需要为该子任务编写测试用例。根据钟点工薪资的计算规则可以分为两个不同的测试用例正常工作时长和加班工作时长。由于场景驱动设计已经确定了履行该原子任务职责的是 HourlyEmployee遵循测试驱动开发的定律一“一次只写一个刚好失败的测试作为新加功能的描述”编写一个刚好失败的测试 public class HourlyEmployeeTest {Testpublic void should_calculate_payroll_by_work_hours_in_a_week() {} } 按照 Given-When-Then 模式来编写该测试方法。首先考虑 HourlyEmployee 聚合的创建。由于钟点工每天都要提交工作时间卡薪资按周结算因此在创建 HourlyEmployee 聚合根的实例时需要传入工作时间卡的列表。计算薪资的方法为 payroll()返回结果为薪资模型对象 Payroll。验证时需确保薪资的结算周期与薪资总额是正确的。故而编写的测试方法为 Testpublic void should_calculate_payroll_by_work_hours_in_a_week() {//givenTimeCard timeCard1 new TimeCard(LocalDate.of(2019, 9, 2), 8);TimeCard timeCard2 new TimeCard(LocalDate.of(2019, 9, 3), 8);TimeCard timeCard3 new TimeCard(LocalDate.of(2019, 9, 4), 8);TimeCard timeCard4 new TimeCard(LocalDate.of(2019, 9, 5), 8);TimeCard timeCard5 new TimeCard(LocalDate.of(2019, 9, 6), 8);ListTimeCard timeCards new ArrayList();timeCards.add(timeCard1);timeCards.add(timeCard2);timeCards.add(timeCard3);timeCards.add(timeCard4);timeCards.add(timeCard5);HourlyEmployee hourlyEmployee new HourlyEmployee(timeCards, Money.of(10000, Currency.RMB));//whenPayroll payroll hourlyEmployee.payroll();//thenassertThat(payroll).isNotNull();assertThat(payroll.beginDate()).isEqualTo(LocalDate.of(2019, 9, 2));assertThat(payroll.endDate()).isEqualTo(LocalDate.of(2019, 9, 6));assertThat(payroll.amount()).isEqualTo(Money.of(400000, Currency.RMB));} 运行测试失败 让失败的测试刚好通过 在实现测试时遵循测试驱动开发定律二“不写任何产品代码除非它刚好能让失败的测试通过”在实现 payroll() 方法时仅提供满足当前测试用例预期的实现。什么是“刚好能让失败的测试通过”以当前测试方法为例。要计算钟点工的薪资除了它提供的工作时间卡之外还需要钟点工的时薪至于 HourlyEmployee 的其他属性暂时可不用考虑当前测试方法没有要求验证工作时间卡的有效性在实现时亦不必验证传入的工作时间卡是否符合要求只需确保为测试方法准备的数据是正确的即可当前测试方法是针对正常工作时长计算薪资实现时就无需考虑加班的情况。实现代码为 public class HourlyEmployee {private ListTimeCard timeCards;private Money salaryOfHour;public HourlyEmployee(ListTimeCard timeCards, Money salaryOfHour) {this.timeCards timeCards;this.salaryOfHour salaryOfHour;}public Payroll payroll() {int totalHours timeCards.stream().map(tc - tc.workHours()).reduce(0, (hours, total) - hours total);Collections.sort(timeCards);return new Payroll(timeCards.get(0).workDay(), timeCards.get(timeCards.size() - 1).workDay(), salaryOfHour.multiply(totalHours));} } 在编写让失败测试通过的代码时要把握好分寸既不要过度地实现测试没有覆盖的内容也无需死板地拘泥于编写所谓“简单”的实现代码。简单并非简陋既然你的编码技能与设计水平已经足以一次编写出优良的代码就不必一定要拖到最后多此一举地等待重构来改进。例如在上述实现代码中需要将工作总小时数乘以 Money 类型的时薪你当然可以实现为如下代码 new Money(salaryOfHour.value() * totalHours, salaryOfHour.currency()) 然而如果你已经熟悉迪米特法则且认识到以数据提供者形式进行对象协作的弊病就会自然地想到应该在 Money 中定义 multiply() 方法而非通过公开 value 和 currency 的 get 访问器让调用者完成乘法计算。这时就可直接实现如下代码而不必等着以后再来进行重构 public class Money {private final long value;private final Currency currency;public static Money of(long value, Currency currency) {return new Money(value, currency);}private Money(long value, Currency currency) {this.value value;this.currency currency;}public Money multiply(int factor) {return new Money(value * factor, currency);}Overridepublic boolean equals(Object o) {if (this o) return true;if (o null || getClass() ! o.getClass()) return false;Money money (Money) o;return value money.value currency money.currency;}Overridepublic int hashCode() {return Objects.hash(value, currency);} } 简单说来在不会导致过度设计的前提下若能直接编写出整洁的代码又何乐而不为呢只需要做到实现的代码仅仅能让测试刚好通过不去过度设计即可。为了让测试方法通过我们定义并实现了 HourlyEmployee、TimeCard 与 Payroll 等领域模型对象。它们的定义都非常简单即使你知道 HourlyEmployee 一定还有 Id 和 name 等基本的核心字段也不必在现在就给出这些字段的定义。利用测试驱动开发来实现领域模型重要的一点就是要用测试来驱动出这些模型对象的定义。只要不会遗漏领域场景就一定会有测试去覆盖这些领域逻辑。一次只做好一件事情即可。 现在测试变绿了 在测试通过的情况下先不要考虑是重构还是编写新的测试而应提交代码。持续集成强调七步提交法其基础就是进行频繁的原子提交。这样就能保证尽快将你的最新变更反馈到团队共享的代码库上降低代码冲突的风险同时也能为重构设定一个安全的回滚版本。 重构产品代码和测试代码 提交代码后根据简单设计原则我们需要检查已有实现与测试代码是否存在重复是否清晰地表达了设计者意图。 先看产品代码目前的实现并没有重复代码但是 payroll() 方法中的代码 Collections.sort(timeCards); 会让人产生困惑为什么需要对工作时间卡排序显然这里缺乏对业务含义的封装直接将实现暴露出来了。排序仅仅是手段我们的目标是获得结算薪资的开始日期和结束日期。由于返回的是两个值且这两个值代表了一个内聚的概念故而可以定义一个内部概念 Peroid。重构的过程是首先提取 beginDate 和 endDate 变量然后定义 Period 内部类 public Payroll payroll() {int totalHours timeCards.stream().map(tc - tc.workHours()).reduce(0, (hours, total) - hours total);Collections.sort(timeCards);LocalDate beginDate timeCards.get(0).workDay();LocalDate endDate timeCards.get(timeCards.size() - 1).workDay();Period settlementPeriod new Period(beginDate, endDate);return new Payroll(settlementPeriod.beginDate, settlementPeriod.endDate, salaryOfHour.multiply(totalHours));}private class Period {private LocalDate beginDate;private LocalDate endDate;Period(LocalDate beginDate, LocalDate endDate) {this.beginDate beginDate;this.endDate endDate;}} 然后再提取方法 settlementPeriod()。该方法名直接体现其业务目标并将包括排序在内的实现细节封装起来 public Payroll payroll() {int totalHours timeCards.stream().map(tc - tc.workHours()).reduce(0, (hours, total) - hours total);return new Payroll(settlementPeriod().beginDate,settlementPeriod().endDate,salaryOfHour.multiply(totalHours));}private Period settlementPeriod() {Collections.sort(timeCards);LocalDate beginDate timeCards.get(0).workDay();LocalDate endDate timeCards.get(timeCards.size() - 1).workDay();return new Period(beginDate, endDate);} 接下来不要忘了对测试代码的重构。毫无疑问创建 List 的逻辑可以封装为一个方法不至于让测试的 Given 部分充斥太多不必要的细节 public class HourlyEmployeeTest {Testpublic void should_calculate_payroll_by_work_hours_in_a_week() {//givenListTimeCard timeCards createTimeCards();Money salaryOfHour Money.of(10000, Currency.RMB);HourlyEmployee hourlyEmployee new HourlyEmployee(timeCards, salaryOfHour);//whenPayroll payroll hourlyEmployee.payroll();//thenassertThat(payroll).isNotNull();assertThat(payroll.beginDate()).isEqualTo(LocalDate.of(2019, 9, 2));assertThat(payroll.endDate()).isEqualTo(LocalDate.of(2019, 9, 6));assertThat(payroll.amount()).isEqualTo(Money.of(400000, Currency.RMB));}private ListTimeCard createTimeCards() {TimeCard timeCard1 new TimeCard(LocalDate.of(2019, 9, 2), 8);TimeCard timeCard2 new TimeCard(LocalDate.of(2019, 9, 3), 8);TimeCard timeCard3 new TimeCard(LocalDate.of(2019, 9, 4), 8);TimeCard timeCard4 new TimeCard(LocalDate.of(2019, 9, 5), 8);TimeCard timeCard5 new TimeCard(LocalDate.of(2019, 9, 6), 8);ListTimeCard timeCards new ArrayList();timeCards.add(timeCard1);timeCards.add(timeCard2);timeCards.add(timeCard3);timeCards.add(timeCard4);timeCards.add(timeCard5);return timeCards;} }
http://www.zqtcl.cn/news/186375/

相关文章:

  • 最好的网站设计公司源码 php多平台网站建设
  • 下载了网站源码施工企业质量管理体系应按照我国
  • 有关网站建设国内外现状的文献英文谷歌seo
  • 珠海做网站哪间好佛山网站建设骏域
  • 免费网站建设支持ftp网络规划设计师资格证
  • 网站打开文件按钮怎么做十大网络游戏
  • 问答类咨询网站的建设烟台开发区做网站
  • 网站域名费用怎么做分录销售crm客户管理系统
  • 海南住房与城乡建设网站大连做网站团队
  • 邯郸最穷的三个县长春纯手工seo
  • 昌黎网站建设贵德县建设局网站
  • 山西网站制作公司兼职做网站安全么
  • 阿里做网站怎么做青岛网站维护
  • 怎么建网站手机版郑州网站建设哪家好
  • 做企业网站有哪些好处安龙网站建设
  • 怎做连接网站wordpress iis设置方法
  • ugc网站开发网站设计常见流程
  • dz论坛可以做招聘网站国内空间没备案可以打开网站吗
  • 建设用地规划证查询网站公司起名字大全免费好听
  • 杭州网站建设公司有哪些瑞诺国际的数字营销模式
  • 宣城网站建设 有限公司高州做网站
  • 做外贸最适合的网站系统有可以做国外支付系统的网站吗
  • 建设执业资格注册中心网站办事大厅ui设计素材库
  • 个人网站免费建站4399电脑版网页链接
  • 重庆开县网站建设公司推荐网站建设与维护高职
  • 关于网站开发的技术博客海口网站设计建设
  • xx市院门户网站建设方案做视频特技的网站
  • 肇庆seo公司咨询23火星seo 网站
  • 天元建设集团有限公司破产新手seo网站做什么类型好
  • spa.net网站开发二次开发需要什么