【问题标题】:Design pattern suggestion/implementation using java 8使用 java 8 的设计模式建议/实现
【发布时间】:2019-12-23 06:55:32
【问题描述】:

我必须通过一系列步骤处理请求。

例如:如果请求 1 来了,那么我必须应用 step1、step2、step3 和最后的 step4,它将处理后的请求持久化到数据库中。

我想实现 模板设计 模式,因为它解决了类似的问题。

当我开始实现设计模式时,我突然发现很难实现,因为逻辑复杂。

让我解释一下要求:

请求 -> 控制器 -> run()

请求将包含List<objects>
run 方法中,会触发一系列操作。

request.parallelStream()
    .map(step1 -> executeStep1.apply(step1))
    .map(step2 -> executeStep2.apply(step2, action))
    .map(step3 -> executeStep3.apply(step3, rules))
    .map(step4 -> executeStep4.apply(step4))
    .collect(Collectors.toList());

    Function<String, List<PersonDto>> executeStep1= person-> {
        return metaData.getMetaDataPerson(person);
    };

    BiFunction<List<PersonDto>, String, TransTemplateDTO> executeStep2= (metaData, action) -> {
        return temlate.createTemplate(metaData, action);
    };

现在,我们可以看到,我将request 的第一个元素作为输入传递给 step1(),然后对其进行处理,并将输出作为输入进一步传递给后续步骤。

  • 问题 1
    到目前为止,没有任何问题。但突然需求发生了变化,现在我必须在 step3 中添加规则逻辑,即executeStep3.apply(step3)

    step3 有 2 个参数,一个是 step2 的输出,第二个是 List 规则。
    Step3 应该应用所有规则并返回与规则相等的结果。
    例如。如果有 3 个规则,则 step3 应该返回一个包含 3 个对象的列表。
    假设 step3 收到 PersonDto List of 10 items 和 List of rules of 3 items,那么 step3 应该返回 10*3 = 30 条记录。
    每个人的规则也将根据命令而有所不同。

  • 问题 2:
    在第 3 步中,我需要请求对象,以便我可以使用值。 像这样:
    .map(step3 -&gt; executeStep3.apply(step3, rules, request))

什么设计模式在这里有帮助?如何?

【问题讨论】:

  • (我看不出与 Spring Boot第八版 Java 或任何定义明确的步骤序列有特殊关系定义了一个抽象解决方案:请在问题中明确说明或删除这些标签。)
  • @greybeard - 如果您可以浏览代码,那么您会注意到我正在使用 parallelStream(),它是 Java 8 的一部分。
  • 不管我能不能,当前是第 13 版,没有任何迹象表明 java.util.Collection.parallelStream() 很快就会被弃用。 java-stream 有一个标签。

标签: java algorithm spring-boot design-patterns java-8


【解决方案1】:

正如dung ta van已经提到的,首先想到的是责任链模式。我将重用该示例并在那里更改一些内容。

public class ChainOfResponsibility {

    protected List<RequestProcessor> handlers = new ArrayList<>();

    public void addHandler(RequestProcessor handler) {
        this.handlers.add(handler);
    }

    @SuppressWarnings("unchecked")
    public void handle(Request request) {
        handlers
                .stream()
                .reduce(RequestProcessor::andThen)
                .orElseThrow(() -> new RuntimeException("Functions can't be composed"))
                .apply(request, null);
    }

    public interface RequestProcessor<T, R> extends BiFunction<Request, T, R> {

        default <V> RequestProcessor<T, V> andThen(BiFunction<Request, ? super R, ? extends V> after) {
            Objects.requireNonNull(after);
            return (Request r, T t) -> after.apply(r, apply(r, t));
        }

    }

    public static class PersonExtractor implements RequestProcessor<Void, PersonDto> {
        @Override
        public PersonDto apply(Request request, Void aVoid) {
            return new PersonDto("Nick");
        }
    }

    public static class ValidatePersonHandler implements RequestProcessor<PersonDto, PersonDto> {
        @Override
        public PersonDto apply(Request request, PersonDto personDto) {
            if (personDto.getName() == null) {
                throw new IllegalArgumentException("name can't be null");
            }
            return personDto;
        }
    }

    public static class SetPersonIdHandler implements RequestProcessor<PersonDto, List<?>> {

        private final List<Rule> rules;

        public SetPersonIdHandler(List<Rule> rules) {
            this.rules = rules;
        }

        @Override
        public List<?> apply(Request request, PersonDto personDto) {
            personDto.setId(1);
            rules.forEach(rule -> System.out.println("invoke rule " + rule.toString()));
            return Arrays.asList(personDto, personDto, personDto);
        }

    }

    public static class InsertPersonToDBHandler implements RequestProcessor<List<PersonDto>, Object> {

        @Override
        public List<?> apply(Request request, List<PersonDto> persons) {
            persons.forEach(person -> System.out.println("insert person: " + person.getName() + " to db"));
            return null;
        }
    }

    public static void main(String[] args) {
        ChainOfResponsibility chain = new ChainOfResponsibility();

        chain.addHandler(new PersonExtractor());
        chain.addHandler(new ValidatePersonHandler());
        chain.addHandler(new SetPersonIdHandler(Arrays.asList(new Rule("1"), new Rule("2"))));
        chain.addHandler(new InsertPersonToDBHandler());

        chain.handle(new Request());
    }
}

简而言之,我们引入了 RequestProcessor 接口,它确实是一个BiFunction。我们将第一个参数绑定到Request,第二个参数是之前函数调用的结果。此外,每个处理程序也可以配置规则。

【讨论】:

    【解决方案2】:

    你应该使用Chain of Responsibility设计模式

    import java.util.ArrayList;
    import java.util.List;
    
    class PersonDto {
        protected int id;
        protected String name;
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    public class ChainOfResponsibility {
    
        protected List<Handler> handlers = new ArrayList<>();
    
        public void addHandler(Handler handler) {
            this.handlers.add(handler);
        }
    
        public void handle(PersonDto person) throws Exception {
            for(Handler handler : handlers)
                handler.handle(person);
        }
    
        public static interface Handler {
    
            void handle(PersonDto person) throws Exception;
    
        }
    
        public static class ValidatePersonHandler implements Handler {
            @Override
            public void handle(PersonDto person) {
                if(person.getName() == null)
                    throw new IllegalArgumentException("name can't be null");
            }
        }
    
        public static class SetPersonIdHandler implements Handler {
            @Override
            public void handle(PersonDto person) {
                person.setId(1);
            }
        }
    
        public static class InsertPersonToDBHandler implements Handler {
            @Override
            public void handle(PersonDto person) {
                // insert to db
                System.out.println("insert person: " + person.getName() + " to db");
            }
        }
    
        public static void main(String[] args) throws Exception {
            ChainOfResponsibility chain = new ChainOfResponsibility();
            chain.addHandler(new ValidatePersonHandler());
            chain.addHandler(new SetPersonIdHandler());
            chain.addHandler(new InsertPersonToDBHandler());
            PersonDto person = new PersonDto();
            person.setName("foo");
            chain.handle(person);
        }
    
    }
    

    【讨论】:

    • 感谢您的回答。你的答案有点接近我的问题,但就我而言,我正在将第一个处理程序的输出转换为不同的对象。但是在您的代码 sn-p 中,您使用了 \same 对象并将其传递给所有处理程序。
    • 你可以使用我的答案,并在Handler.handle函数后附加一个output参数,例如:void handle(PersonDto person, Map output)
    • 是的,我可以,但是在每个处理程序之后,都会有新的输出格式。
    猜你喜欢
    • 1970-01-01
    • 2012-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-08
    • 2015-09-16
    • 2017-12-03
    相关资源
    最近更新 更多