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

时间:2015-08-01 03:48:53

标签: java design-patterns architecture

我想在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<Employee> employeeList = null;

public ProjectManager() {
    employeeList = new ArrayList<Employee>();
}

public List<Employee> getEmployees() {
    return employeeList;
}

public void setEmployees(List<Employee> 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<ProgrammingLanguages> languagesList = null;

private int workload = 0;

public Developer() {
    languagesList = new ArrayList<ProgrammingLanguages>();
}

public void setLanguagesList(List<ProgrammingLanguages> languagesList) {
    this.languagesList = languagesList;
}

public void addProgrammingLanguage(ProgrammingLanguages language) {
    languagesList.add(language);
}

public List<ProgrammingLanguages> getLanguagesList() {
    return languagesList;
}

public void setWorkload(int workload) {
    this.workload = workload;
}

public int getWorkload() {
    return workload;
}

}

不幸的是,我的ProjectManager课程中出现编译错误,不知道为什么?

提前致谢。

3 个答案:

答案 0 :(得分:1)

  

我对这种设计模式并不百分之百确定,但我认为这是这种情况的完美用例,不是吗?

Composite的GoF结构如下:

GoF Composite pattern

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

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

答案 1 :(得分:0)

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

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

顺便说一句,这不是作曲模式 - 这是继承。你可以(而且应该)read more关于它。

答案 2 :(得分:0)

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

您需要以下参与者:

  1. abstractEmployee必须声明合成的接口并在一定程度上实现常见行为。
  2. ProjectManager类扩展了abstractEmployee并实现了一个行为来处理Employee个孩子,i.d。在您的情况下ProjectManagerDeveloper个实例。
  3. Developer还扩展了abstractEmployee,代表了一个没有任何孩子的叶子。
  4. 我使用您的示例代码来演示复合模式。请注意,它可能与您期望的结果不同,但您可以将其作为参考。

    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<Employee> getEmployees() {
            throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED);
        }
    
        public Employee setEmployees(List<Employee> employees) {
            throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED);
        }
    
        public Employee setLanguagesList(List<ProgrammingLanguages> languagesList) {
            throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED);
        }
    
        public Employee addProgrammingLanguage(ProgrammingLanguages language) {
            throw new UnsupportedOperationException(OPERATION_NOT_SUPPORTED);
        }
    
        public List<ProgrammingLanguages> 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<Employee> 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<Employee> getEmployees() {
            return this.employeeList;
        }
    
        @Override
        public Employee setEmployees(List<Employee> 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<ProgrammingLanguages> languagesList = null;
    
        private int workload = 0;
    
        public Developer() {
            this.languagesList = new ArrayList<>();
        }
    
        @Override
        public Employee setLanguagesList(List<ProgrammingLanguages> languagesList) {
            this.languagesList = languagesList;
            return this;
        }
    
        @Override
        public Employee addProgrammingLanguage(ProgrammingLanguages language) {
            this.languagesList.add(language);
            return this;
        }
    
        @Override
        public List<ProgrammingLanguages> 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
    }
    

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

    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

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

    Tree_structure_Composite_Pattern

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

相关问题