Java中的复合设计模式


在这里,我为您提供了另一个有用的设计模式-复合设计模式。我将尝试指出在为您实现复合模式时要记住的关键功能。

Composite Design Pattern 该复合设计模式是指“将对象组合成树形结构来表示部分-整体层次结构。Composite模式使得客户对单个对象和复合对象的统一”。

  • 所述Composite Design Pattern描述,可以以同样的方式被视为相同的对象类型的单个实例的对象组。
  • 该Composite Design Pattern允许我们“撰写”对象成树形结构以表示部分-整体层次结构。
  • 此外,Composite Design Pattern还允许我们的客户以相同的方式对待单个对象和构图。
  • 该Composite Design Pattern让我们能够有一个树形结构为执行任务的每个节点。
  • 在面向对象的程序设计中,复合对象是设计为由一个或多个相似对象组成的对象,这些对象均具有相似的功能。这被称为对象之间的“具有”关系。

以下是Composite Design Pattern中使用的classes/objects的列表,该列表有四个:

Component – Component是用于组成对象的接口(或抽象类),以及用于访问/处理其子组件或节点组件的方法。它还实现了一个默认接口,以定义所有组件类的通用功能/行为。 Leaf – 叶子类定义了一个具体的组件类,没有任何进一步的组成。叶子类实现组件接口。它仅在最后执行命令/任务。 Composite – Composite类定义了一个具体的组件类,该类存储其子组件。复合类实现组件接口。它将命令/任务转发到它包含的复合对象。它还可以在转发interact/manipulate之前和之后执行其他操作。 Client –Client 类使用组件接口来交互/操纵合成中的对象(Leaf and Composite)。

pattern.png

为了更好地理解这一点,让我们看一个在组织中工作的员工的示例。

Steps 我们创建一个接口来定义要作为复合对象和叶对象执行的功能。下面是Worker接口的代码,其中包含assignWork()和方法performWork()。Work在示例中,该界面将充当复合模式的组成部分。

package org.trishinfotech.composite;
public interface Worker {
    void assignWork(Employee manager, Work work);
    void performWork();
}

工作类被定义为如下:

package org.trishinfotech.composite;
import java.util.ArrayList;
import java.util.List;
public class Work {

    private Calculator workType;
    private List<String> work = new ArrayList<String>();

    public Work(Calculator workType, List<String> work) {
        super();
        this.workType = workType;
        this.work = work;
    }

    public Calculator getWorkType() {
        return workType;
    }

    public void setWorkType(Calculator workType) {
        this.workType = workType;
    }

    public List<String> getWork() {
        return work;
    }

    public void setWork(List<String> work) {
        this.work = work;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("Work [workType=").append(workType).append(", work=").append(work).append("]");
        return builder.toString();
    }

}

为了简化示例,在这里我仅处理简单的计算,例如阶乘值和回文和Armstrong检验。由于Pandirome也可以是字符串,因此我在Work课堂上一直从事String的工作。下面的类定义了执行阶乘,回文和阿姆斯特朗的算法/公式。这是计算器 枚举的代码:

package org.trishinfotech.composite;
import java.math.BigInteger;
public enum Calculator {
    FACTORIAL {
        @Override
        public String calculate(String value) {
            String answer = "NA";
            try {
                long longValue = Long.parseLong(value);
                BigInteger factorialValue = BigInteger.valueOf(1);
                for (long i = 1; i <= longValue; i++) {
                    factorialValue = factorialValue.multiply(BigInteger.valueOf(i));
                }
                answer = factorialValue.toString();
            } catch (NumberFormatException exp) {
                System.out.println("Can't calculate factorial of " + value);
            }
            return answer;
        }
    },

    PALINDROME {
        @Override
        public String calculate(String value) {
            String answer = "false";
            if (value != null && !value.trim().isEmpty()) {
                String reverse = (new StringBuilder(value).reverse().toString());
                answer = Boolean.toString(reverse.equals(value));
            }
            return answer;
        }
    },

    ARMSTRONG {
        @Override
        public String calculate(String value) {
            String answer = "false";
            try {
                long longValue = Long.parseLong(value);
                long number = longValue;
                long armstrongValue = 0;
                while (number != 0) {
                    long temp = number % 10;
                    armstrongValue = armstrongValue + temp * temp * temp;
                    number /= 10;
                }
                answer = Boolean.toString(String.valueOf(armstrongValue).equals(value));
            } catch (NumberFormatException exp) {
                System.out.println("Can't calculate armstrong of " + value);
            }
            return answer;
        }
    };

    public abstract String calculate(String value);

}

I have created these algorithms as enums. To read more on Java-Enums, please refer to my article (Java Enums: How to Make Enums More Useful).

We will create an abstract class of Employee to carry the common code for all various concrete subclasses of the employees.

package org.trishinfotech.composite;
public abstract class Employee implements Worker {

    protected long employeeId;
    protected String employeeName;
    protected String designation;
    protected Department department;

    public Employee(long employeeId, String employeeName, String designation, Department department) {
        super();
        this.employeeId = employeeId;
        this.employeeName = employeeName;
        this.designation = designation;
        this.department = department;
    }

    public long getEmployeeId() {
        return employeeId;
    }

    public void setEmployeeId(long employeeId) {
        this.employeeId = employeeId;
    }

    public String getEmployeeName() {
        return employeeName;
    }

    public void setEmployeeName(String employeeName) {
        this.employeeName = employeeName;
    }

    public String getDesignation() {
        return designation;
    }

    public void setDesignation(String designation) {
        this.designation = designation;
    }

    public Department getDepartment() {
        return department;

    }

    public void setDepartment(Department department) {
        this.department = department;
    }

    public abstract int teamSize();

    public String fullDetails() {
        StringBuilder builder = new StringBuilder();
        builder.append("Employee [").append(employeeId).append(", ").append(employeeName).append(", ")
                .append(designation).append(", ").append(department).append(", Team=").append(teamSize()).append("]");
        return builder.toString();

    }

    public String shortDetails() {
        StringBuilder builder = new StringBuilder();
        builder.append("'").append(employeeName).append("'");
        return builder.toString();
    }

    @Override
    public String toString() {
        return shortDetails();
    }

}

The Employeeclass declares abstract method teamSize() which I will use to split the work load assigned from a manager to anEngineer. So teamSize() will will be 1 forEngineer where as it will give the number of employees theManager is managing.

TheEngineer class is as below:

package org.trishinfotech.composite;
import java.util.ArrayList;
import java.util.List;
public class Engineer extends Employee {

    private List<Work> works = new ArrayList<Work>();

    public Engineer(long employeeId, String employeeName, String designation, Department department) {
        super(employeeId, employeeName, designation, department);
    }

    @Override
    public int teamSize() {
        return 1;
    }

    @Override
    public void assignWork(Employee manager, Work work) {
        this.works.add(work);
        System.out.println(this + " has assigned work of '" + work + "' by manager " + manager);
    }

    @Override
    public void performWork() {
        System.out.println(this + " is performing work of '" + works + "'");
        works.stream().forEach(work -> {
            work.getWork().stream().forEach(value -> {
                Calculator calculator = work.getWorkType();
                System.out.println(this + " has result of work of '" + work + "' as : " + calculator.calculate(value));
            });
        });
        works.clear();
    }

}

We will create the Manager class to use as the composite object, and we will have another Employee object as a collection via the composition. The Manager class is as below:

package org.trishinfotech.composite;

import java.util.ArrayList;
import java.util.List;
public class Manager extends Employee {

    List<Employee> managingEmployees = new ArrayList<Employee>();

    public Manager(long employeeId, String employeeName, String designation, Department department) {
        super(employeeId, employeeName, designation, department);
    }

    public boolean manages(Employee employee) {
        return managingEmployees.add(employee);
    }

    public boolean stopManaging(Employee employee) {
        return managingEmployees.remove(employee);
    }

    @Override
    public int teamSize() {
        return managingEmployees.stream().mapToInt(employee -> employee.teamSize()).sum();

    }

    @Override
    public void assignWork(Employee manager, Work work) {
       System.out.println(this + " has assigned work of '" + work + "' by manager " + manager);
        System.out.println();
        System.out.println(this + " distributing work '" + work + "' to managing-employees..");
         int fromIndex = 0;
        int toIndex = 0;
        int totalWork = work.getWork().size();
        List<String> assignWork = null;
        while (toIndex < totalWork) {
            for (Employee employee : managingEmployees) {
                System.out.println("Assigning to " + employee);
                int size = employee.teamSize();
                toIndex = fromIndex + size;
                assignWork = work.getWork().subList(fromIndex, toIndex);
                if (assignWork.isEmpty()) {
                    return;
                }
                employee.assignWork(this, new Work(work.getWorkType(), assignWork));
                fromIndex = toIndex;
            }
            break;
        }
    }

    @Override
    public void performWork() {
        System.out.println(this + " is asking his managing employees to perform assigned work");
        System.out.println();
        managingEmployees.stream().forEach(employee -> employee.performWork());
        System.out.println();
        System.out.println(this + " has completed assigned work with the help of his managing employees");
        System.out.println();
    }

}

We define Work in the property file instead of hard-coding into theMain class. The work.propertiesis defined as below:

Calculate.Palindrome=1234321, 12341234, ABCDEDCBA, 4567887654, XYZZYX, 45676543, 3456543
Calculate.Armstrong=153, 8208, 2104, 4210818, 345321, 32164049651, 876412347
Calculate.Factorial=20, 43, 15, 120, 543, 35, 456, 432, 350, 44, 26, 17, 8

The Main class usesWorkLoader class to load work from the work.properties. TheWorkLoader class is defined as below:

package org.trishinfotech.composite;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.Set;
public class WorkLoader {
    protected Properties properties = new Properties();
    public WorkLoader(String fileName) {
        try (InputStream input = new FileInputStream(fileName)) {
            // load a properties file
            properties.load(input);
        } catch (IOException exp) {
            exp.printStackTrace();
        }
    }
    public Properties getProperties() {
        return properties;
    }
    public List<Work> getWorkList() {
        List<Work> workList = new ArrayList<Work>();
        Set<Object> keys = properties.keySet();
        for (Object key : keys) {
            String workType = key.toString().substring("Calculate".length() + 1).toUpperCase();
            String values = properties.getProperty(key.toString());
            Work work = new Work(Calculator.valueOf(workType), Arrays.asList(values.split(", ")));
            workList.add(work);
        }
        return workList;
    }

}

最后,我们将把Main类编写为,Client以执行和测试我们的复合模式代码。

package org.trishinfotech.composite;
public class Main {
    public static void main(String[] args) {
        Engineer ajay = new Engineer(1001l, "Ajay", "Developer", Department.ENG);
        Engineer vijay = new Engineer(1002l, "Vijay", "SR. Developer", Department.ENG);
        Engineer jay = new Engineer(1003l, "Jay", "Lead", Department.ENG);
        Engineer martin = new Engineer(1004l, "Martin", "QA", Department.ENG);
        Manager kim = new Manager(1005l, "Kim", "Manager", Department.ENG);
        Engineer anders = new Engineer(1006l, "Andersen", "Developer", Department.ENG);
        Manager niels = new Manager(1007l, "Niels", "Sr. Manager", Department.ENG);
        Engineer robert = new Engineer(1008l, "Robert", "Developer", Department.ENG);
        Manager rachelle = new Manager(1009l, "Rachelle", "Product Manager", Department.ENG);
        Engineer shailesh = new Engineer(1010l, "Shailesh", "Engineer", Department.ENG);

        kim.manages(ajay);
        kim.manages(martin);
        kim.manages(vijay);
        niels.manages(jay);
        niels.manages(anders);
        niels.manages(shailesh);

        rachelle.manages(kim);
        rachelle.manages(robert);
        rachelle.manages(niels);

        WorkLoader workLoad = new WorkLoader("work.properties");
        workLoad.getWorkList().stream().forEach(work -> {

            rachelle.assignWork(rachelle, work);
        });

        rachelle.performWork();

    }

}

下面是程序的输出:

'Rachelle' has assigned work of 'Work [workType=FACTORIAL, work=[20, 43, 15, 120, 543, 35, 456, 432, 350, 44, 26, 17, 8]]' by manager 'Rachelle'
'Rachelle' distributing work 'Work [workType=FACTORIAL, work=[20, 43, 15, 120, 543, 35, 456, 432, 350, 44, 26, 17, 8]]' to managing-employees..
Assigning to 'Kim'
'Kim' has assigned work of 'Work [workType=FACTORIAL, work=[20, 43, 15]]' by manager 'Rachelle'

'Kim' distributing work 'Work [workType=FACTORIAL, work=[20, 43, 15]]' to managing-employees..
Assigning to 'Ajay'
'Ajay' has assigned work of 'Work [workType=FACTORIAL, work=[20]]' by manager 'Kim'
Assigning to 'Martin'
'Martin' has assigned work of 'Work [workType=FACTORIAL, work=[43]]' by manager 'Kim'
Assigning to 'Vijay'
'Vijay' has assigned work of 'Work [workType=FACTORIAL, work=[15]]' by manager 'Kim'
Assigning to 'Robert'
'Robert' has assigned work of 'Work [workType=FACTORIAL, work=[120]]' by manager 'Rachelle'
Assigning to 'Niels'
'Niels' has assigned work of 'Work [workType=FACTORIAL, work=[543, 35, 456]]' by manager 'Rachelle'

'Niels' distributing work 'Work [workType=FACTORIAL, work=[543, 35, 456]]' to managing-employees..
Assigning to 'Jay'
'Jay' has assigned work of 'Work [workType=FACTORIAL, work=[543]]' by manager 'Niels'
Assigning to 'Andersen'
'Andersen' has assigned work of 'Work [workType=FACTORIAL, work=[35]]' by manager 'Niels'
Assigning to 'Shailesh'
'Shailesh' has assigned work of 'Work [workType=FACTORIAL, work=[456]]' by manager 'Niels'
'Rachelle' has assigned work of 'Work [workType=PALINDROME, work=[1234321, 12341234, ABCDEDCBA, 4567887654, XYZZYX, 45676543, 3456543]]' by manager 'Rachelle'

'Rachelle' distributing work 'Work [workType=PALINDROME, work=[1234321, 12341234, ABCDEDCBA, 4567887654, XYZZYX, 45676543, 3456543]]' to managing-employees..
Assigning to 'Kim'
'Kim' has assigned work of 'Work [workType=PALINDROME, work=[1234321, 12341234, ABCDEDCBA]]' by manager 'Rachelle'

'Kim' distributing work 'Work [workType=PALINDROME, work=[1234321, 12341234, ABCDEDCBA]]' to managing-employees..
Assigning to 'Ajay'
'Ajay' has assigned work of 'Work [workType=PALINDROME, work=[1234321]]' by manager 'Kim'
Assigning to 'Martin'
'Martin' has assigned work of 'Work [workType=PALINDROME, work=[12341234]]' by manager 'Kim'
Assigning to 'Vijay'
'Vijay' has assigned work of 'Work [workType=PALINDROME, work=[ABCDEDCBA]]' by manager 'Kim'
Assigning to 'Robert'
'Robert' has assigned work of 'Work [workType=PALINDROME, work=[4567887654]]' by manager 'Rachelle'
Assigning to 'Niels'
'Niels' has assigned work of 'Work [workType=PALINDROME, work=[XYZZYX, 45676543, 3456543]]' by manager 'Rachelle'

'Niels' distributing work 'Work [workType=PALINDROME, work=[XYZZYX, 45676543, 3456543]]' to managing-employees..
Assigning to 'Jay'
'Jay' has assigned work of 'Work [workType=PALINDROME, work=[XYZZYX]]' by manager 'Niels'
Assigning to 'Andersen'
'Andersen' has assigned work of 'Work [workType=PALINDROME, work=[45676543]]' by manager 'Niels'
Assigning to 'Shailesh'
'Shailesh' has assigned work of 'Work [workType=PALINDROME, work=[3456543]]' by manager 'Niels'
'Rachelle' has assigned work of 'Work [workType=ARMSTRONG, work=[153, 8208, 2104, 4210818, 345321, 32164049651, 876412347]]' by manager 'Rachelle'

'Rachelle' distributing work 'Work [workType=ARMSTRONG, work=[153, 8208, 2104, 4210818, 345321, 32164049651, 876412347]]' to managing-employees..
Assigning to 'Kim'
'Kim' has assigned work of 'Work [workType=ARMSTRONG, work=[153, 8208, 2104]]' by manager 'Rachelle'
'Kim' distributing work 'Work [workType=ARMSTRONG, work=[153, 8208, 2104]]' to managing-employees..
Assigning to 'Ajay'
'Ajay' has assigned work of 'Work [workType=ARMSTRONG, work=[153]]' by manager 'Kim'
Assigning to 'Martin'
'Martin' has assigned work of 'Work [workType=ARMSTRONG, work=[8208]]' by manager 'Kim'
Assigning to 'Vijay'
'Vijay' has assigned work of 'Work [workType=ARMSTRONG, work=[2104]]' by manager 'Kim'
Assigning to 'Robert'
'Robert' has assigned work of 'Work [workType=ARMSTRONG, work=[4210818]]' by manager 'Rachelle'
Assigning to 'Niels'
'Niels' has assigned work of 'Work [workType=ARMSTRONG, work=[345321, 32164049651, 876412347]]' by manager 'Rachelle'
'Niels' distributing work 'Work [workType=ARMSTRONG, work=[345321, 32164049651, 876412347]]' to managing-employees..
Assigning to 'Jay'
'Jay' has assigned work of 'Work [workType=ARMSTRONG, work=[345321]]' by manager 'Niels'
Assigning to 'Andersen'
'Andersen' has assigned work of 'Work [workType=ARMSTRONG, work=[32164049651]]' by manager 'Niels'
Assigning to 'Shailesh'
'Shailesh' has assigned work of 'Work [workType=ARMSTRONG, work=[876412347]]' by manager 'Niels'
'Rachelle' is asking his managing employees to perform assigned work

'Kim' is asking his managing employees to perform assigned work

'Ajay' is performing work of '[Work [workType=FACTORIAL, work=[20]], Work [workType=PALINDROME, work=[1234321]], Work [workType=ARMSTRONG, work=[153]]]'
'Ajay' has result of work of 'Work [workType=FACTORIAL, work=[20]]' as : 2432902008176640000
'Ajay' has result of work of 'Work [workType=PALINDROME, work=[1234321]]' as : true
'Ajay' has result of work of 'Work [workType=ARMSTRONG, work=[153]]' as : true
'Martin' is performing work of '[Work [workType=FACTORIAL, work=[43]], Work [workType=PALINDROME, work=[12341234]], Work [workType=ARMSTRONG, work=[8208]]]'
'Martin' has result of work of 'Work [workType=FACTORIAL, work=[43]]' as : 60415263063373835637355132068513997507264512000000000
'Martin' has result of work of 'Work [workType=PALINDROME, work=[12341234]]' as : false
'Martin' has result of work of 'Work [workType=ARMSTRONG, work=[8208]]' as : false
'Vijay' is performing work of '[Work [workType=FACTORIAL, work=[15]], Work [workType=PALINDROME, work=[ABCDEDCBA]], Work [workType=ARMSTRONG, work=[2104]]]'
'Vijay' has result of work of 'Work [workType=FACTORIAL, work=[15]]' as : 1307674368000
'Vijay' has result of work of 'Work [workType=PALINDROME, work=[ABCDEDCBA]]' as : true
'Vijay' has result of work of 'Work [workType=ARMSTRONG, work=[2104]]' as : false

'Kim' has completed assigned work with the help of his managing employees

'Robert' is performing work of '[Work [workType=FACTORIAL, work=[120]], Work [workType=PALINDROME, work=[4567887654]], Work [workType=ARMSTRONG, work=[4210818]]]'
'Robert' has result of work of 'Work [workType=FACTORIAL, work=[120]]' as : 6689502913449127057588118054090372586752746333138029810295671352301633557244962989366874165271984981308157637893214090552534408589408121859898481114389650005964960521256960000000000000000000000000000
'Robert' has result of work of 'Work [workType=PALINDROME, work=[4567887654]]' as : true
'Robert' has result of work of 'Work [workType=ARMSTRONG, work=[4210818]]' as : false
'Niels' is asking his managing employees to perform assigned work

'Jay' is performing work of '[Work [workType=FACTORIAL, work=[543]], Work [workType=PALINDROME, work=[XYZZYX]], Work [workType=ARMSTRONG, work=[345321]]]'
'Jay' has result of work of 'Work [workType=FACTORIAL, work=[543]]' as : 872891556790260456843586366934462570217404467584986862157951660218033476207283552939973350537069217537549478114229971312262991181125700413163606116971183695586311579361173915852193241844683585564114537080099157013082576149573523335369738442355599816710804068865355684599942047453968407440725166640261015140054933542126214585902983116193907129111747665196041855032660956095883694974186998924247749529335931094092429725640658310042199668214202637924631140057800119930627800378541111012271243379033822559451085315416955672912791395237932595257653475479021208979154389591618595449855779925751308303314870067464075830210893226767964127916083986194604372529850059441599156750579670067110415997949767860963439005485252514342425180564330056392659552281473502353159284918610493411467800558076001750687023376509841526414457026571388047691226042613278047076078395826335028468047405871941546558134196554638340479908186429178241794558954878506078646531853505428187507441610683354213870320835243780540993795316813622383436151335642255741817696689682127415809984693167490611336830354021351607247261703154384913620088006020923947745280000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
'Jay' has result of work of 'Work [workType=PALINDROME, work=[XYZZYX]]' as : true
'Jay' has result of work of 'Work [workType=ARMSTRONG, work=[345321]]' as : false
'Andersen' is performing work of '[Work [workType=FACTORIAL, work=[35]], Work [workType=PALINDROME, work=[45676543]], Work [workType=ARMSTRONG, work=[32164049651]]]'
'Andersen' has result of work of 'Work [workType=FACTORIAL, work=[35]]' as : 10333147966386144929666651337523200000000
'Andersen' has result of work of 'Work [workType=PALINDROME, work=[45676543]]' as : false
'Andersen' has result of work of 'Work [workType=ARMSTRONG, work=[32164049651]]' as : false
'Shailesh' is performing work of '[Work [workType=FACTORIAL, work=[456]], Work [workType=PALINDROME, work=[3456543]], Work [workType=ARMSTRONG, work=[876412347]]]'
'Shailesh' has result of work of 'Work [workType=FACTORIAL, work=[456]]' as : 150777392777717065903328562798297482932764849966301315324902295697797980802999492049275470580840593582700556154654997912467653672836190567363944536581444396786039028419417159553169852939652733499484374432647121409002713034716885273557660568294514238651304204026421026217797122437474581042706674997505548774529387552185264469304745879944335896334980134727576771262477699704913814778801164976379963316514713032786305083016847394455111607701177156363125206697642497352441989049637406799105387152093299654856194446887474831405921359722324720996553956200165400519069670468845686118517860926559421327845227712982865242890852011587912148558934925229259778865164753102371910801614732061965104129730561590839408147446252948841011789641706225763887234100676084552005497753764496546383864694159909979495432469993306110242973486330432796522331628915418533758582252153753291412897349335363154308911927972242304805109760000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
'Shailesh' has result of work of 'Work [workType=PALINDROME, work=[3456543]]' as : true
'Shailesh' has result of work of 'Work [workType=ARMSTRONG, work=[876412347]]' as : false

'Niels' has completed assigned work with the help of his managing employees

'Rachelle' has completed assigned work with the help of his managing employees

在这里,我没有使用并发来简化示例。请根据您的选择随意完善该示例。


原文链接:http://codingdict.com