Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用模式避免ifs_Java_Oop_Design Patterns - Fatal编程技术网

Java 使用模式避免ifs

Java 使用模式避免ifs,java,oop,design-patterns,Java,Oop,Design Patterns,我知道,通过使用策略或命令模式的多态性,可以删除if块。但是,假设我的代码如下所示: ArgumentObject arg = getArg(); if (arg.getId() == "id2_1" || arg.getId() == "id3_1" || arg.getId() == "id4_1") { //do something } if (arg.getId() == "id2_1") { //do something } if (arg.getId() = "id

我知道,通过使用策略或命令模式的多态性,可以删除if块。但是,假设我的代码如下所示:

ArgumentObject arg = getArg();

if (arg.getId() == "id2_1" || arg.getId() == "id3_1" || arg.getId() == "id4_1") {
    //do something
}
if (arg.getId() == "id2_1") {
    //do something
}
if (arg.getId() = "id2_2" || arg.getId() = "id3_1") {
    //do something
}
if (arg.getId().startsWith("id1") || arg.getId().startsWith("id4")) {
    //do something
}
基本上,代码根据产品的id执行一些字段填充操作。它检查产品是否来自具有startsWith()的某组产品,然后执行填充,检查产品是否具有特定id,然后适当填充字段,等等


我不知道如何在这里使用策略模式?如果我创建了一个策略来处理第一个If语句,那么如何处理第二个语句呢?问题在于,国际单项体育联合会并不是相互排斥的。我是否应该将相关的ifs转移到策略类?有没有什么模式可以帮助我重构它,使其更易于测试?

您的代码揭示的问题更为基本:它违反了Tell!不要问!原则


您的
arg
对象不应该有一个方法
getId()。待完成的工作可以在实例化时注入到
arg
对象中,或者可以将它们作为参数传递给方法,并且
arg
对象的具体实现决定调用哪个参数…

您的问题缺少这些ifs的业务逻辑。 但我可以从以下方面做出一些假设:

基本上,代码根据产品的id执行一些字段填充操作。它检查产品是否来自具有startsWith()的某组产品,然后执行填充,检查产品是否具有特定id,然后适当填充字段,等等

我假设所有模块都是特定的业务逻辑,并且彼此独立。 你可以试试这个装饰图案。正如维基所说:

Decorator模式是一种设计模式,它允许静态或动态地将行为添加到单个对象,而不影响同一类中其他对象的行为

您的案例可以被视为:

public Product{

    private String id;
    //other fields
}


   ProductDecoratorInterface{

       Product populateItem(Product product);

    }

ProductXYZDecorator{

   @Override
   public Product populateItem(Product product){
   // check the id for 1,2,3
   //do the field population

}

}

    ProductABCDecorator{

    @Override
    public Product populateItem(Product product){
    // check the id for 1,3
    //do the field population

    }

    }
您的主类将如下所示:

public Mainclass{

List<ProductDecoratorInterface> decorators;


public void someFn(Product product){
   decorators.stream.forEach(i -> i.populateItem(product));
}

}
public类{
列出装饰师;
公共产品{
decorators.stream.forEach(i->i.populateItem(产品));
}
}
}

有没有什么模式可以帮助我重构它,让它更容易测试

在这里,您只需要测试单个装饰器

您需要维护所有decorator的列表,并将对象传递给所有decorator。
这不是对模式的正确使用,但有助于解决您的用例(测试复杂性)。

如果完全基于
的代码,您可能无法摆脱
,但您可以将其整理成更合适的类

如果
是域逻辑,并且在域中有意义,那么您可以编写一个单独负责此分类的对象:

 interface ArgumentClassifier {
      Classification classify(Argument arg);
 }
分类
将是一个
枚举

这个实现将包含
if
s,封装该域逻辑

  • 您可以单独对
    ArgumentClassifier
    进行单元测试
  • 如果您的
    ArgumentClassifier
    变得又大又复杂,那么您可以使用复合模式将其分解
  • 如果您以后找到不同的分类方法(例如,规则引擎、数据库查找等),您可以编写
    ArgumentClassifier
    的新实现
现在,您可以使用策略模式:

  Map<Classification, Handler> strategies = ...;
  ArgumentClassifier classifier = new SimpleArgumentClassifier();

  private Foo handleArg(Argument arg) {
      return strategies
          .get(classifier.classify(arg))
          .handle(arg);  
  }
这为失业的17岁男性提供了
0b001
分类,为就业的17岁女性提供了
0b010
分类,依此类推

您可以直接将它们用作策略图的键(可以是多对一)。或者,您可以进一步进行逐位操作,将它们减少到一个较小的集合


这里有很多范围,但注意不要忽略简单性和清晰性。有时,一系列的
if/else
完成了任务,这是明确而有效的。

我真的看不出有什么理由在这种情况下尝试使用策略模式。也许如果您以更现实的方式解释业务问题,您可以得到更现实的解决方案。此外,您应该使用
equals()
方法而不是
==
来比较字符串。您的代码可以减少:第二个和第三个
if
在将代码复制到第一个
if
中时是多余的,类中有大约100个if语句,我必须为它编写单元测试。我认为将一些代码提取到策略中会使测试变得更小、更容易编写,并且只需在其他测试中使用逻辑测试策略……是的,它们是冗余的,因为这只是一个示例。在应用程序中,每个if都是必需的。嗯,我们的体系结构中的参数对象只是一个普通的传输对象,不包含任何业务逻辑,并且始终是相同的。通过填写UI表单生成。然后,基于此对象,创建包含不同数据库调用数据的新数据传输对象。然后,来自数据库的响应对象被合并到最终的响应对象中,以便进一步使用。我无法在arg对象中添加任何逻辑:(您的建议似乎仍然类似于策略模式,对于不同的对象,我会有不同的行为,对于操作对象的不同策略也是一样。@eek“我们架构中的参数对象只是一个简单的传输对象,不包含任何业务逻辑”在这种情况下,您应该通过一个工厂来创建包装器对象,该对象具有处理每个ID所需的逻辑。注意,我已经从
ArgumentObject
的名称中删除了“Object”一词。所有对象都是对象,因此在类名中包含“Object”一词是重复的。
 int classification(Person p) {
     return 0
         | ( p.getGender() == Gender.MALE ? 1 : 0 )
         | ( p.isEmployed()               ? 2 : 0 )
         | ( p.age >= 18                  ? 4 : 0 );
 }