【问题标题】:Using strategy or additional class?使用策略或附加类?
【发布时间】:2020-10-14 11:37:57
【问题描述】:

我有以下代码示例(代码如下)。

我有接口OnlyReverseOnlySplit,它们定义了对Data 类的操作。有时我的课程仅可用于倒车,有时我将能够进行倒车和拆分。

在代码中我有两种方法。

第一种方法是为这 2 个单独的用例 ReverseAndSplitImplOnlyReverseImpl 使用 2 个单独的类。在这里我不喜欢我需要额外的类,并且我需要在这两个类之间复制一些代码。

第二种方法是为两个用例SingleClassForReverseAndSplitImpl 使用一个类,然后使用策略注入NormalSplitNoSplit。这里我不喜欢这个额外的NoSplit 类,它基本上是人为的。

根据接口分离原则——我需要有ReverseAndSplit加入接口,还是应该总是分开使用两个接口(比如SingleClassForReverseAndSplitImpl implements OnlyReverse, OnlySplit而不是SingleClassForReverseAndSplitImpl implements ReverseAndSplit)?

从长远来看,其中哪种方法更好(将来更灵活)?

class Data{
  String a;
}

interface OnlyReverse{
  Data getData();
  OnlyReverse reverse();
}

interface OnlySplit{
  OnlySplit split();
}

interface ReverseAndSplit extends OnlyReverse, OnlySplit{
  @Override
  ReverseAndSplit reverse();
  @Override
  ReverseAndSplit split();
}

//------------------------- USE DISTINCT CLASSES; ONE HAS SPLIT OTHER NO

class ReverseAndSplitImpl implements ReverseAndSplit{
  Data data;

  public ReverseAndSplitImpl(Data data) {
    this.data = data;
  }

  @Override
  public Data getData() {
    return data;
  }

  @Override
  public ReverseAndSplit reverse() {
    //here reverse and return
    return new ReverseAndSplitImpl(data);
  }

  @Override
  public ReverseAndSplit split() {
    //here split and return
    return new ReverseAndSplitImpl(data);
  }
}

class OnlyReverseImpl implements OnlyReverse{
  Data data;

  public OnlyReverseImpl(Data data) {
    this.data = data;
  }

  @Override
  public Data getData() {
    return data;
  }

  @Override
  public OnlyReverse reverse() {
    return new OnlyReverseImpl(data);
  }
}

//------------------------- USE DISTINCT CLASSES; ONE HAS SPLIT OTHER NO

//------------------------- USE STRATEGY TO CHOOSE TO HAVE SPLITTING OR NO
interface SplitStrategy{
  Data split(Data data);
}
class NormalSplit implements SplitStrategy{
  @Override
  public Data split(Data data) {
    return new Data();
  }
}
//NullObject pattern
class NoSplit implements SplitStrategy{
  @Override
  public Data split(Data data) {
    return data;
  }
}

class SingleClassForReverseAndSplitImpl implements ReverseAndSplit{
  Data data;
  SplitStrategy splitStrategy;

  public SingleClassForReverseAndSplitImpl(Data data, SplitStrategy splitStrategy) {
    this.data = data;
    this.splitStrategy = splitStrategy;
  }

  @Override
  public Data getData() {
    return data;
  }

  @Override
  public ReverseAndSplit reverse() {
    //here reverse and return
    return new SingleClassForReverseAndSplitImpl(data, splitStrategy);
  }

  @Override
  public ReverseAndSplit split() {
    //here split and return
    SingleClassForReverseAndSplitImpl s = new SingleClassForReverseAndSplitImpl(data, splitStrategy);
    s.data = splitStrategy.split(data);
    return s;
  }
}
//------------------------- USE STRATEGY TO CHOOSE TO HAVE SPLITTING OR NO

public class Decorator {

  public static void main(String[] args) {

    ReverseAndSplit s11 = new SingleClassForReverseAndSplitImpl(new Data(), new NoSplit());
    s11 = s11.reverse();
    s11 = s11.split();  //has split operation, but NoSplit will do nothing

    OnlyReverse s12 = new OnlyReverseImpl(new Data());
    s12 = s12.reverse();
    //has no split operation present

    //Going from NoSplit to SplitAndReverse
    ReverseAndSplit s21 = new SingleClassForReverseAndSplitImpl(s11.getData(), new NormalSplit());
    s21 = s21.reverse();
    s21 = s21.split();  //has split and now it is using NormalSplit

    ReverseAndSplit s22 = new ReverseAndSplitImpl(s12.getData());
    s22 = s22.reverse();
    s22 = s22.split();

  }
}

【问题讨论】:

  • 提供替代方案/ReverseAndSplit 不一定是 的事情,坏的是让您的代码依赖于那些更具体的接口。出于实现目的,通常更容易聚合和利用单个接口

标签: java oop design-patterns strategy-pattern


【解决方案1】:

我想使用您的第一种方法(两个更简单的接口)但不叫它们OnlyReverseOnlySplit 而是ReverseSplit 是合理的。因此将它们组合起来是合理的,将来您也可以只使用其中之一。

但这也取决于您的域对象,因此很难为您做出选择。但我不会创建一个名为NoSplit 的接口,因为您仍然可以实现ReverseAndSplit NoSplit,这对您来说毫无意义。

【讨论】:

    【解决方案2】:

    根据接口隔离原则,如果您有一个从不拆分的客户端,那么您不应向该客户端提供包含split 方法的接口。策略/空对象方法适用于有时需要拆分而其他时候不需要的单个客户。单独的接口方法适用于具有不同需求的两个不同的客户。

    【讨论】:

    • split 是可以对内部数据执行的附加功能(如果策略设置为空对象,则不能执行)。其他关于逻辑的一切都应该保持不变。我猜那是单客户端方法...
    • 基本上,通过使用这种方法,我想阻止一些 SingleClassForReverseAndSplitImplsplit 并让其他一些人允许它 - 例如基于我初始化它的Data。如果数据设置为“1”、“2”、“3” - 则允许split,否则使用NoSplit
    • @MarkoKraljevic 客户如何知道他们是否可以调用 split ?他们将如何处理无法拆分/反转的问题?目前尚不清楚客户端将如何使用这些类和接口。
    • @plalx 我猜他们不会。因为我可以有逻辑在我的类中初始化策略,但方法 split() 将始终存在。只是有时如果被调用它什么也不做。有没有像第一种更好的方法,但不复制相同的代码?就像将所有相同的方法委托给父级一样,并且在内部只处理单个 split() 。但是然后-如何在委托类中访问Data
    • @MarkoKraljevic 调用 "string".split() 并让它什么都不做,你感觉如何?客户会编写算法来操作数据吗?如果我们不知道客户将如何使用这些接口和类,我们将无法在设计中提供帮助。
    猜你喜欢
    • 1970-01-01
    • 2020-03-02
    • 1970-01-01
    • 2019-02-18
    • 2015-08-04
    • 2020-09-27
    • 2021-08-24
    • 2017-05-17
    • 1970-01-01
    相关资源
    最近更新 更多