- 任务由经理分配给员工。 一项任务可以分配给许多员工。
- 员工将他在某些任务上工作的小时数填满至系统。
- 经理/员工查看时间表上的报告(时间表可以更改)。
让我们稍微回顾一下这些要点,然后尝试将这种简单的人类语言转换为程序员可以发现的某些关系和实体。
- 实体:经理,员工,时间表,任务
好的,我们现在应该对领域有了更好的了解,所以让我们创建maven项目并实现类。 使用Maven,您将获得漂亮而干净的项目结构。 您所需要做的就是安装Maven,并在项目中包含pom.xml。 您可以“手动”执行此操作,并通过终端构建应用程序(在这种情况下,只需创建常规项目并添加pom.xml文件)。 我更喜欢使用一些其他工具。 IntelliJ IDEA,NetBeans和Springsource Tool Suite具有现成的Maven支持。 如果您使用的是纯Eclipse,请检查m2eclipse插件。
无论哪种方式,这都是我们项目的一些基本Maven配置:
<project xmlns='http://maven.apache.org/POM/4.0.0'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xsi:schemaLocation='http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd'>
<modelVersion>4.0.0</modelVersion>
<groupId>org.timesheet</groupId>
<artifactId>org.timesheet</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Timesheet Management On Spring</name>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
现在让我们实现领域模型。 创建包org.timesheet.domain并定义以下类。
package org.timesheet.domain;
public class Employee {
private String name;
private String department;
public Employee(String name, String department) {
this.name = name;
this.department = department;
}
public String getName() {
return name;
}
public String getDepartment() {
return department;
}
}
package org.timesheet.domain;
public class Manager {
private String name;
public Manager(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
package org.timesheet.domain;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Task {
private List<Employee> assignedEmployees = new ArrayList<Employee>();
private Manager manager;
private boolean completed;
private String description;
public Task(String description, Manager manager, Employee... employees) {
this.description = description;
this.manager = manager;
assignedEmployees.addAll(Arrays.asList(employees));
completed = false;
}
public Manager getManager() {
return manager;
}
public List<Employee> getAssignedEmployees() {
return assignedEmployees;
}
public void addEmployee(Employee e) {
assignedEmployees.add(e);
}
public void removeEmployee(Employee e) {
assignedEmployees.remove(e);
}
public void completeTask() {
completed = true;
}
}
package org.timesheet.domain;
public class Timesheet {
private Employee who;
private Task task;
private Integer hours;
public Timesheet(Employee who, Task task, Integer hours) {
this.who = who;
this.task = task;
this.hours = hours;
}
public Employee getWho() {
return who;
}
public Task getTask() {
return task;
}
public Integer getHours() {
return hours;
}
/**
* Manager can alter hours before closing task
* @param hours New amount of hours
*/
public void alterHours(Integer hours) {
this.hours = hours;
}
@Override
public String toString() {
return 'Timesheet [who=' + who + ', task=' + task + ', hours=' + hours
+ ']';
}
}
如您所见,Manager和Employee类没有很多属性,它们在这里只是为了拥有类型安全模型。 在“现实世界”中,他们可能还有其他各种属性,例如姓,生日,地址等等,甚至可能是普通的父类。
而且,我们现在并不真正在乎各种约束。 例如,我们只能在任务上填写整数小时,依此类推。
现在是时候定义我们的服务层–定义业务操作并为这些操作建立接口。 因此,让我们制作软件包org.timesheet.service 。 首先,我们将创建GenericDao接口,在其中我们将为系统中的每个实体定义基本的CRUD操作。
package org.timesheet.service;
import java.util.List;
public interface GenericDao<E, K> {
void add(E entity);
void update(E entity);
void remove(E entity);
E find(K key);
List<E> list();
}
现在,让我们不必担心实际的持久层-让我们创建一些虚拟实现并将所有数据存储在内存中。 我们将其放入新包– org.timesheet.service.impl中 。 不用担心,稍后我们将使用Hibernate。 这是虚拟实现的代码:
package org.timesheet.service.impl;
import java.util.ArrayList;
import java.util.List;
import org.timesheet.service.GenericDao;
public class InMemoryDao<E, K> implements GenericDao<E, K> {
private List<E> entities = new ArrayList<E>();
@Override
public void add(E entity) {
entities.add(entity);
}
@Override
public void update(E entity) {
throw new UnsupportedOperationException('Not supported in dummy in-memory impl!');
}
@Override
public void remove(E entity) {
entities.remove(entity);
}
@Override
public E find(K key) {
if (entities.isEmpty()) {
return null;
}
// just return the first one sice we are not using any keys ATM
return entities.get(0);
}
@Override
public List<E> list() {
return entities;
}
}
接下来,我们将编写我们的第一个简单测试。 现在,我们将第一个依赖项添加到pom.xml文件的JUnit库中。 因为它是第一个,所以我们还需要将其包装到dependencies元素中,如下所示:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
</dependencies>
这是我们针对Employee DAO的第一个非常简单的单元测试。 我们现在不做其他任何事情,因为我们还没有真正要测试的东西。 但是,更重要的是,我们如何依赖测试中DAO的实现(我们使用新的InMemoryDao… )。 这很不好,因为我们应该只测试定义接口的公共API。 在本教程的后面,您将看到Spring如何帮助我们解决此类问题。
package org.timesheet.service;
import static org.junit.Assert.*;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.timesheet.domain.Employee;
import org.timesheet.service.impl.InMemoryDao;
public class EmployeeDaoTest {
private GenericDao<Employee, Long> employeeDao = new InMemoryDao<Employee, Long>();
@Before
public void setUp() {
for (int i = 0; i < 5; i++) {
Employee e = new Employee('Mike ' + i, 'IT');
employeeDao.add(e);
}
}
@Test
public void testAdd() {
int oldSize = employeeDao.list().size();
Employee e = new Employee('Bob', 'IT');
employeeDao.add(e);
int newSize = employeeDao.list().size();
assertFalse (oldSize == newSize);
}
@Test
public void testRemove() {
int oldSize = employeeDao.list().size();
Employee e = employeeDao.find(1L);
employeeDao.remove(e);
int newSize = employeeDao.list().size();
assertFalse (oldSize == newSize);
}
@Test
public void testUpdate() {
//TODO: need real implementation
}
@Test
public void testList() {
List<Employee> list = employeeDao.list();
assertNotNull (list);
assertFalse (list.isEmpty());
}
}
如果需要,还可以为其他DAO的其余测试编写单元测试。 但是由于我们现在没有合适的实现来测试,因此我们稍后将一起进行测试。
事情并非总是那么容易。 这不仅与CRUD操作有关,还与业务操作不够通用,无法用简单的DAO表示出来。 因此,让我们定义一些业务操作并为其创建单独的服务。 我们将其称为TimesheetService。
package org.timesheet.service;
import org.timesheet.domain.Employee;
import org.timesheet.domain.Manager;
import org.timesheet.domain.Task;
import java.util.List;
/**
* Business that defines operations on timesheets
*/
public interface TimesheetService {
/**
* @return Finds the busiest task (with the most of employees).
* Returns {@code null} when tasks are empty.
*/
Task busiestTask();
/**
* Finds all the tasks for the employee.
* @param e Employee
* @return Tasks
*/
List<Task> tasksForEmployee(Employee e);
/**
* Finds all the tasks for the manager.
* @param m Manager
* @return Tasks
*/
List<Task> tasksForManager(Manager m);
}
好的,到目前为止很好。 您现在已经知道在下一个示例中我们将使用什么业务领域。 您可能现在想知道-我们还没有使用Spring,为什么呢? 请记住, Spring的最初目的是简化企业Java开发并鼓励POJO开发模型。 因此,将Spring与该基本模型一起使用将非常容易,因此我们不会将核心逻辑与不必要的依赖项混合在一起。
在下面的图片中,到目前为止,我们已经构建了项目的结构,因此请确保您表现良好。
参考: 第1部分–在vrtoonjava博客上,由我们的JCG合作伙伴 Michal Vrtiak 设计域模型和服务层 。
翻译自: https://www.javacodegeeks.com/2012/09/spring-designing-domain-model-and.html