我试图将注意力集中在如何最好地设计我正在研究的系统上。

假设它是类似于典当行的应用程序。我已经将购买和转售流程限制为一种称为ExecutionStrategy的流程。此应用程序中有四个ExecutionStrategy实现:注册客户,投标和购买,定价以及过帐到商店。

每个策略都遵循一个基本步骤,包括主要执行工作流程并记录我们在数据存储区中所做的工作。

除了这些投标,购买以及定价之外,在执行工作流中执行任何操作之前,还需要咨询专家。

这就是我对设计方面要做出的决定感到困惑的地方。似乎有三个选项可供选择,我不太确定哪个是最正确的。 1)使用带有ExecutionStrategyWithConsultation的ExecutionStrategy之类的东西来扩展执行策略,该策略将策略的执行工作流程包装为咨询阶段。 2)为ExecutionStrategy创建Decorator模式,并使用ConsultationServiceDecorator之类的方式扩展它。 3)在购买/投标和定价的实现中创建一个成员变量,以随时通过围绕该服务的接口调用咨询服务。

我将在下面概述设计。

一些注意事项:


ConsultationService非常非常慢。缓存并不是真正的选择,因为数据的格式非常松散,我们不想为此创建文档数据存储。
ConsultationService返回与给定对象匹配的对象。因此它最终只有一种看起来像T consultOn(T item)的方法
在执行工作流中随时可能需要调用ConsultationService。当前,唯一的用例是在主流之前调用服务,但这不一定是目前唯一的用例。


每种方法的利弊:


直接扩展ExecutionStrategy:


PRO:我们可以在代码中访问受保护的ConsultationService变量
PRO:通过阅读诸如PurchasingExecutionStrategy extends ExecutionStrategyWithConsultation的代码,我们有了一个了解,因此,我们从中了解了什么样的工作流程。
缺点:这似乎打破了“组成继承”的模式。我们正在使用继承来存储成员变量。
缺点:服务返回了一个全新的对象,因此在对服务进行调用的第一行代码之后,我们正在处理的对象与原始传递的对象完全不同。

创建一个装饰器:


赞成:我们与继承主体的构成更加一致。
PRO:我们可以强制首先调用该服务,然后将该新对象传递给主工作流程,因此它仅对传递的对象执行其主工作流程。
缺点:我还没有找到一种设计方法来允许潜在的多次或任何时间的服务呼叫。
缺点:在查看代码时,我们会失去从PurchasingExecutionStrategy extends ExecutionStrategyWithConsultation获得的知识,除非我们将PurchasingExecutionStrategy实际实例化为ConsultationServiceDecorator的构造函数arg的地方

使用接口创建成员变量:


优点:与#1相同。易于理解,无需深入挖掘代码在做什么。
缺点:与#1相同。无法执行订单。执行处理的对象与传递的对象本质上不同。
缺点:如果我们需要在同一工作流程中进行多个调用,由于服务速度快且没有缓存,这将非常慢。



每个示例:

//Number 1
public interface ExecutionStrategy<T> {

    /**
    * Perform the main execution workflow
    */
    public T execute(T item);
}

public interface ConsultationService {

    public StoreItem consultOn (StoreItem item);
}

public abstract class ExecutionStrategyWithConsultation implements ExecutionStrategy<StoreItem> {

    protected ConsultationService consultationService;

}

public class ListingExecutionStrategy extends ExecutionStrategyWithConsultation {

    public StoreItem execute(StoreItem item) {
      if (item.hasDirectBuyer()) { //hasDirectBuyer is populated by ConsultationService
        item.sellTo = item.directBuyer.getId();
      } else {
        //no direct buyer
        SuggestedPriceRange priceRange = item.getConsultationPriceRange(); //consultationPriceRange is populated by ConsultationService
        item.priceRange = priceRange;
        item.listToWebsite = true;
      }
      return item;
    }
}




//Number 2
public interface ExecutionStrategy<T> {

    /**
    * Perform the main execution workflow
    */
    public T execute(T item);
}

public abstract class ExecutionStrategyDecorator<T> implements ExecutionStrategy<T>{

    protected final ExecutionStrategy<T> executionStrategy;
    public ExecutionStrategyDecorator(ExecutionStrategy<T> execStrategy) {
      executionStrategy = execStrategy;
    };
}

public class ExecutionStrategyWithConsultation extends ExecutionStrategyDecorator<StoreItem> {

    protected ConsultationService consultationService;

    public ExecutionStrategyWithConsultation(ExecutionStrategy<StoreItem> execStrat, ConsultationService service) {
      super(execStrat);
      consultationService = service;
    }

    public StoreItem execute(StoreItem item) {
      StoreItem itemAfterConsultation = consultationService.consultOn(item);
      return execStrategy.execute(itemAfterConsultation);
    }

}

public class ListingExecutionStrategy implements ExecutionStrategy<StoreItem> {

    public StoreItem execute(StoreItem item) {
      if (item.hasDirectBuyer()) { //hasDirectBuyer is populated by ConsultationService
        item.sellTo = buyer.getId();
      } else {
        //no direct buyer
        SuggestedPriceRange priceRange = item.getConsultationPriceRange(); //consultationPriceRange is populated by ConsultationService
        item.priceRange = priceRange;
        item.listToWebsite = true;
      }
      return item;
    }
}

public class ListingExecutionStrategyFactory {

    public ExecutionStrategy instantiate() {
      return new ExecutionStrategyWithConsultation(new ListingExecutionStrategy(), new ConsultationServiceImpl());
    }
}




//Number 3
public interface ExecutionStrategy<T> {

    /**
    * Perform the main execution workflow
    */
    public T execute(T item);
}

public interface ConsultationService {

    public DirectBuyer getDirectBuyerIfExists(StoreItemType itemType);
    public SuggestedPriceRange getSuggestedPriceRange(StoreItem item);
}

public class ListingExecutionStrategy implements ExecutionStrategy<StoreItem> {

    ConsultationService service;

    public PurchasingExecutionStrategy(ConsultationService consultService) {
        service = ConsultationService;
    }

    public StoreItem execute(StoreItem item) {
      DirectBuyer buyer = service.getDirectBuyerIfExists(item.getItemType())
      if (Optional.ofNullable(buyer).isPresent()) {
        item.sellTo = buyer.getId();
        return item;
      } else {
        //no direct buyer
        SuggestedPriceRange priceRange = service.getSuggestedPriceRange(item);
        item.priceRange = priceRange;
        item.listToWebsite = true;
        return item;
      }
    }
}


感谢您的输入。感谢帮助。

最佳答案

作为ConsultationService的替代方法,您可以考虑构建ExecutionService实例链以允许创建复杂的处理方案:

public interface ExecutionStrategy<T> {
    public T execute(T item);
}


public interface ExecutionStrategyChain<T> extends ExecutionStrategy<T> {
    public static <T> ExecutionStrategyChain<T> newInstance(ExecutionStrategy<T> executionStrategy) {
        return new ExecutionStrategyChainImpl<T>(executionStrategy);
    }

    public ExecutionStrategyChain<C> chainTo(ExecutionStrategy<C> executionStrategy);
}


public abstract class AbstractExecutionStrategyChain<T> implements ExecutionStrategyChain<T> {
    protected AbstractExecutionStrategyChain() {
        this(null);
    }


    public abstract T execute(T item);


    public ExecutionStrategyChain<T> chainTo(ExecutionStrategy<T> executionStrategy) {
        return new ExecutionStrategyChainImpl<T>(this, executionStrategy);
    }
}


public final class ExecutionStrategyChainImpl<T> extends AbstractExecutionStrategyChain<T> {

    private final ExecutionStrategy<T> firstExecutionStrategy;
    private final Executionstrategy<T> secondExecutionStrategy;

    public ExecutionStrategyChainImpl(ExecutionStrategy<T> first, ExecutionStrategy<T> second) {
        if(first == null) throw new NullPointerException();
        this.firstExecutionStrategy = first;
        this.secondExecutionStrategy = second;
    }

    public ExecutionStrategyChainImpl(ExecutionStrategy<T> first) {
        this(first, null);
    }

    @Override
    public final T execute(T item) {
        if(item == null) {
            return null;
        }

        T result = firstExecutionStrategy.execute(item);
        if(result != null && secondExecutionStrategy != null) {
            result = secondExecutionStrategy.execute(result);
        }
        return result;
    }
}


public class PreProcessor<T> implements ExecutionStrategy<T> {

    public PreProcessor() {
    }

    @Override
    public T execute(T item) {
       //Do some pre-processing of item
       return item;
    }
}


public class PostProcessor<T> implements ExecutionStrategy<T> {

    public PostProcessor() {
    }

    @Override
    public T execute(T item) {
       //Do some post-processing of item
       return item;
    }
}


public class MyNormalProcessor<T> extends AbstractExecutionStrategyChain<T> {

    public MyNormalProcessor() {
    }

    @Override
    public T execute(T item) {
       //Do something normal with the item
       return item;
    }
}


public static final ExecutionStrategy<StoreItem> COMPLEX_EXECUTION_STRATEGY =
    ExecutionStrategyChain<StoreItem>.newInstance(new PreProcessor<StoreItem>())
                                     .chainTo(new MyNormalProcessor<StoreItem>())
                                     .chainTo(new PostProcessor<StoreItem>());

关于java - 何时使用成员变量与按组成设计?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56224883/

10-09 19:55