如何在Java中实现复合模式?

我想在Java中实现一个复合模式,以映射软件开发组织。 所以,我们假设有多个项目经理和多个开发人员。 每个开发人员只分配给一个项目经理,每个开发人员都能够使用各种编程语言进行编码。 项目经理带领开发人员并确切地知道他们的工作量。

我不是百分百肯定这个设计模式,但我认为这是这个场景的完美用例,不是吗?

结果应如下:

我想查询项目经理,检查所有能够使用特定编程语言编写代码的开发人员的工作量,例如Java

这是我到目前为止:

Employee.java:

 public class Employee { private String name = null; public Employee() { name = "Noob"; } public String getName() { return name; } public void setName(String name) { this.name = name; } } 

ProgrammingLanguages.java:

 public enum ProgrammingLanguages { JAVA, JAVASCRIPT, C, PHP, SWIFT, PYTHON } 

ProjectManager.java:

 import java.util.ArrayList; import java.util.List; public class ProjectManager extends Employee { private List employeeList = null; public ProjectManager() { employeeList = new ArrayList(); } public List getEmployees() { return employeeList; } public void setEmployees(List employees) { employeeList = employees; } public int getTotalWorkload() { int workload = 0; for (Employee employee : employeeList) { workload += employee.getWorkload(); // Error! Cannot resolve method 'getWorkload()' } return workload; } } 

开发商:

 import java.util.ArrayList; import java.util.List; public class Developer extends Employee { private List languagesList = null; private int workload = 0; public Developer() { languagesList = new ArrayList(); } public void setLanguagesList(List languagesList) { this.languagesList = languagesList; } public void addProgrammingLanguage(ProgrammingLanguages language) { languagesList.add(language); } public List getLanguagesList() { return languagesList; } public void setWorkload(int workload) { this.workload = workload; } public int getWorkload() { return workload; } } 

不幸的是,我在ProjectManager类中遇到编译器错误,任何想法为什么?

提前致谢。

是的,如果要映射树结构,复合模式确实是正确的选择。 参考您的示例,复合设计模式意味着您的类Employee充当节点,类ProjectManager充当分支,类Developer充当叶子。 在这种情况下,复合图案的主要优点是它可以均匀地处理你作品的对象。 因此,您可以使用此特定GoF设计模式表示实例的整个层次结构。

您需要以下参与者:

  1. abstractEmployee必须声明组合的接口并在一定程度上实现共同的行为。
  2. ProjectManager类扩展了abstractEmployee并在您的案例ProjectManagerDeveloper实例中实现了一个处理Employee子代的行为。
  3. Developer还扩展了abstractEmployee并表示没有任何子节点的叶子。

我使用您的示例代码来演示复合模式。 请注意,它可能与您期望的结果不同,但您可以将其作为参考。

Employee.java (节点):

 package me.eckhart; import java.util.List; public abstract class Employee { private String name = null; public static final String OPERATION_NOT_SUPPORTED = "Operation not supported."; public String getName() { return name; } public Employee setName(String name) { if (name == null) throw new IllegalArgumentException("Argument 'name' is null."); this.name = name; return this; } public Employee addEmployee(Employee employee) { throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED); } public List getEmployees() { throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED); } public Employee setEmployees(List employees) { throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED); } public Employee setLanguagesList(List languagesList) { throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED); } public Employee addProgrammingLanguage(ProgrammingLanguages language) { throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED); } public List getLanguagesList() { throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED); } /* Composite operations. */ public abstract int getWorkload(ProgrammingLanguages language); public abstract Employee setWorkload(int workload); } 

ProjectManager.java (分支):

 package me.eckhart; import java.util.ArrayList; import java.util.List; public class ProjectManager extends Employee { private List employeeList = null; public ProjectManager() { this.employeeList = new ArrayList<>(); } @Override public Employee addEmployee(Employee employee) { if (employee == null) throw new IllegalArgumentException("Argument 'employee' is null."); this.employeeList.add(employee); return this; } @Override public List getEmployees() { return this.employeeList; } @Override public Employee setEmployees(List employeeList) { if (employeeList == null) throw new IllegalArgumentException("Argument 'employeeList' is null."); this.employeeList = employeeList; return this; } /* Composite operations. */ public int getWorkload(ProgrammingLanguages language) { int workload = 0; for (Employee employee : employeeList) { workload += employee.getWorkload(language); } return workload; } public Employee setWorkload(int workload) { throw new UnsupportedOperationException(Employee.OPERATION_NOT_SUPPORTED); } } 

Developer.java (叶子):

 package me.eckhart; import java.util.ArrayList; import java.util.List; public class Developer extends Employee { private List languagesList = null; private int workload = 0; public Developer() { this.languagesList = new ArrayList<>(); } @Override public Employee setLanguagesList(List languagesList) { this.languagesList = languagesList; return this; } @Override public Employee addProgrammingLanguage(ProgrammingLanguages language) { this.languagesList.add(language); return this; } @Override public List getLanguagesList() { return this.languagesList; } /* Composite operations. */ public Employee setWorkload(int workload) { if (workload < -1) throw new IllegalArgumentException("Workload cannot be negative."); this.workload = workload; return this; } public int getWorkload(ProgrammingLanguages language) { if (this.languagesList.contains(language)) return workload; return 0; } } 

ProgrammingLanguages.java (枚举):

 package me.eckhart; public enum ProgrammingLanguages { JAVA, JAVASCRIPT, C, PHP, SWIFT, PYTHON } 

我创建了一个unit testing来演示如何访问一种特定编程语言的工作负载。

EmployeeTest.java (JUnit 4.11):

 package me.eckhart; import org.junit.Assert; import org.junit.Before; import org.junit.Test; public class EmployeeTest { protected Employee projectManagerIt; @Before public void setUp() throws Exception { Employee webDevSr = new Developer(); webDevSr.setName("Jane").addProgrammingLanguage(ProgrammingLanguages.JAVASCRIPT).addProgrammingLanguage(ProgrammingLanguages.PYTHON).setWorkload(10); Employee webDevJr = new Developer(); webDevJr.setName("Alex").addProgrammingLanguage(ProgrammingLanguages.PHP).setWorkload(15); Employee projectManagerWebDev = new ProjectManager(); projectManagerWebDev.setName("James").addEmployee(webDevSr).addEmployee(webDevJr); Employee softwareDevSr = new Developer(); softwareDevSr.setName("Martin").addProgrammingLanguage(ProgrammingLanguages.C).addProgrammingLanguage(ProgrammingLanguages.JAVA).setWorkload(35); Employee softwareDevJr = new Developer(); softwareDevJr.setName("John").addProgrammingLanguage(ProgrammingLanguages.JAVA).setWorkload(30); Employee projectManagerBackend = new ProjectManager(); projectManagerBackend.setName("Tom").addEmployee(softwareDevSr).addEmployee(softwareDevJr); Employee freelanceSoftwareDev = new Developer(); freelanceSoftwareDev.setName("Marco").addProgrammingLanguage(ProgrammingLanguages.JAVA).addProgrammingLanguage(ProgrammingLanguages.PYTHON).addProgrammingLanguage(ProgrammingLanguages.C).setWorkload(25); Employee freelanceWebDev = new Developer(); freelanceWebDev.setName("Claudio").addProgrammingLanguage(ProgrammingLanguages.SWIFT).addProgrammingLanguage(ProgrammingLanguages.JAVASCRIPT).addProgrammingLanguage(ProgrammingLanguages.PHP).setWorkload(10); Employee freelanceProjectManager = new ProjectManager(); freelanceProjectManager.setName("Angie").addEmployee(freelanceSoftwareDev).addEmployee(freelanceWebDev); projectManagerIt = new ProjectManager(); projectManagerIt.setName("Peter").addEmployee(projectManagerWebDev).addEmployee(projectManagerBackend).addEmployee(freelanceProjectManager); } @Test public void testComposite() throws Exception { Assert.assertEquals(90, projectManagerIt.getWorkload(ProgrammingLanguages.JAVA)); Assert.assertEquals(20, projectManagerIt.getWorkload(ProgrammingLanguages.JAVASCRIPT)); Assert.assertEquals(60, projectManagerIt.getWorkload(ProgrammingLanguages.C)); Assert.assertEquals(25, projectManagerIt.getWorkload(ProgrammingLanguages.PHP)); Assert.assertEquals(10, projectManagerIt.getWorkload(ProgrammingLanguages.SWIFT)); Assert.assertEquals(35, projectManagerIt.getWorkload(ProgrammingLanguages.PYTHON)); } } 

UML类图如下所示:

UML_class_diagram_composite_design_pattern_GoF

EmployeeTest.javasetUp()方法中的代码实现以下树结构:

Tree_structure_Composite_Pattern

复合设计模式的主要缺点是您需要使用运行时检查来限制某些操作,因为客户端通常不知道它们是在处理ProjectManager (分支)还是Developer (叶子)实例。

我不是百分百肯定这个设计模式,但我认为这是这个场景的完美用例,不是吗?

Composite的GoF结构如下:

GoF复合图案

如您所见, Operation()在所有元素中都很常见。 这将是您的方案的getWorkload()方法。

但是,它与模式有些不一致,因为它意味着Manager的工作负载由她的员工组成。 在现实生活中,情况恰恰相反,至少与一位优秀的经理人相比。 我建议将方法名称更改为getEffortUnderMyResponsibility() ,以表示完成工作的责任,而不是实际完成工作。 对于程序员来说,他们确实是这样做的; 对于经理来说,他们有责任完成任务。

getWorkload()方法未在类Employee中定义,您尝试访问它。

为了解决编译错误,您应该将此方法添加到Employee中 – 我会将其添加为abstract ,以强制任何(新)子类实现它。

顺便说一下,那不是构图模式 – 这是inheritance。 您可以(并且应该) 阅读更多相关信息。