面向对象编程:实现新类需要额外的参数

4
假设我有以下接口:
public interface ConditionChecker {
    boolean isInCondition(Person p);
}

我想创建一个实现上述接口的新类,但我需要实现一个带有另一个参数的函数。
public class MacroConditionChecker implements ConditionChecker {
    public boolean isInCondition(Person p, MacroView mv);
}

两个问题:
一:如果我将接口签名更改为 boolean isInCondition(Person p, MacroView mv);,那么我需要更新所有实现 ConditionChecker 接口的类。
二:我希望 ConditionChecker 的使用者可以直接调用 isInCondition 方法。

我认为这意味着:

public class MacroConditionChecker implements ConditionChecker {
    private static final MacroView mv;
    public MacroConditionChecker(MacroView mv) {
        this.mv = mv;
    }
    public boolean isInCondition(Person p){
        // now i have access to MacroView
    }
}

那么,我需要做的唯一改变是在决定使用MacroConditionChecker并且调用isInCondition时不改变。

我走对了吗?还是有其他方法可以实现这个目标?

或者我应该将MacroView作为自己的接口分离出来?

public class MacroConditionChecker implements ConditionChecker implements MacroView

这确实是其中一种可能的解决方案。但是它有一个不必要的永久状态排序。如果你只是在接口中创建一个新方法,调用带有默认限定符的重载方法呢? - Yassin Hajaj
你的第一个解决方案很不错。但是为什么你把 mv 字段声明为静态的呢? - Ken Bekov
@YassinHajaj,您能再详细解释一下吗?我不是完全明白。 - ealeon
你是否将多个 ConditionChecker 类传递到一个函数中,然后循环调用 isInCondition 来一次性检查所有条件?这可以解释你不想改变该接口的原因。如果是这样,我认为你的解决方案很好。 - aridlehoover
3个回答

1
考虑到MacroConditionChecker无法遵守ConditionChecker的签名,那么实现它的意义是什么?
也许更好的方法是将MacroConditionChecker class转换为一个interface,该接口扩展ConditionChecker
interface MacroConditionChecker extends ConditionChecker {
   boolean isInCondition(final Person person, final MacroView macroView);
}

然后提供一个默认/简单的实现(或您需要的任何内容)

class SimpleMacroConditionChecker implements MacroConditionChecker {
   public boolean isInCondition(final Person person, final MacroView macroView) {
      ...
   }
}

需要使用MacroView来检查条件的人只需接受MacroConditionChecker
public boolean check(final MacroConditionChecker checker) {
   return checker.isInCondition(this.person, this.macroView);
}

就我个人而言,我认为它们是两个完全独立的 接口,但扩展方法仍然不错。
要谨慎选择,特别是如果它们将在许多地方使用。


我认为这并没有解决我提到的第二个问题。假设我有许多对象使用ConditionalChecker并调用isInCondition。如果它使用MacroConditionChecker,现在我需要去修改所有调用isInCondition的地方。如果我回滚MacroConditionChecker,我需要再次进行相同的更改。我正在尝试最小化,以便可以无缝替换ConditionChecker的逻辑。 - ealeon
1
@ealeon,正如我所说,如果有人需要额外的MacroView来进行检查,那么它应该接受一个MacroConditionChecker。这是最惯用和正确的方法。因此,是的,你将不得不进行重构。 - LppEdd

1

由于接口只要求您实现给定的方法,因此您可以使用您想要的参数重载该方法,并在传递额外参数时运行适当的实现。

public class MacroConditionChecker implements ConditionChecker {
    boolean isInCondition(Person p) {};
    public boolean isInCondition(Person p, MacroView mv) {};
}

1
但是这并没有解决我提到的第二个问题,即ConditionChecker的消费者现在需要调用一个额外的参数。例如,如果我决定MacroConditionChecker不再是默认值,我需要去所有的地方进行更改,以便它只使用一个参数进行调用,对吧? - ealeon
Java足够智能,可以调用与该对象类匹配的方法,并在调用期间使用与传递给它的参数匹配的方法实现。这将允许您仅使用两个输入参数调用MacroConditionChecker对象上的isInCondition方法,而不会改变类外部的任何内容,也不会影响仅使用“Person”作为输入的其他调用。 - Bruce S.
这样做的作用就是允许您在输入两个参数的情况下调用MacroConditionChecker对象上的isInCondition。这正是我试图避免的确切更改。如果现在有1000个对象想要使用MacroConditionChecker的isInCondition,我不想进行1000次更改。 - ealeon
这样做可以避免在创建过程中创建1000个对象并为所有对象设置MacroView,而是创建一个单一的对象来处理您希望检查的任何MacroView。 - Bruce S.
如果我不想将MacroConditionChecker作为默认值,并且仅有某些ConditionChecker消费者使用具有一个参数的不同ConditionChecker。重点是我不应该需要对ConditionChecker的消费者进行任何更改,是吗? - ealeon

1
ConditionChecker提醒Command设计模式。链接页面的评论如下:

命令将调用操作的对象与知道如何执行操作的对象分离开来。为了实现这种分离,设计师创建了一个抽象基类,它将接收器(一个对象)与操作(指向成员函数的指针)映射起来。基类包含一个execute()方法,它只是在接收器上调用操作。

这正是你需要的。如果你只想检查Person对象的内部状态,那就足够了。当您想要使用外部API检查Person对象时,在构造函数中绑定外部API并在方法中绑定Person对象即可。简单的例子:
import java.util.ArrayList;
import java.util.List;

public class DesignPatterns {

    public static void main(String[] args) {
        List<ConditionChecker> checkers = new ArrayList<>();
        checkers.add(person -> person != null);
        checkers.add(person -> person.getName() != null);
        checkers.add(person -> person.getName().length() > 0);
        checkers.add(new MacroViewConditionChecker(new MacroView()));
        checkers.add(new RestApiConditionChecker(new RestApi()));

        Person person = new Person();
        person.setName("Name");

        for (ConditionChecker checker : checkers) {
            System.out.println(checker.isInCondition(person));
        }
    }
}

interface ConditionChecker {

    boolean isInCondition(Person person);
}

class MacroViewConditionChecker implements ConditionChecker {

    private final MacroView macroView;

    public MacroViewConditionChecker(MacroView macroView) {
        this.macroView = macroView;
    }

    @Override
    public boolean isInCondition(Person person) {
        return macroView != null;
    }
}

class MacroView {
}

class RestApiConditionChecker implements ConditionChecker {

    private final RestApi restApi;

    public RestApiConditionChecker(RestApi restApi) {
        this.restApi = restApi;
    }

    @Override
    public boolean isInCondition(Person person) {
        return restApi.checkName(person.getName());
    }
}

class RestApi {

    public boolean checkName(String name) {
        System.out.println("Validate name ...");
        System.out.println(name + " is valid");

        return true;
    }
}

class Person {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

你可以与责任链一起使用此模式。这种方法不会将Person对象与任何实现绑定在一起。这种绑定是在特定的ConditionChecker实现中完成的,可以很容易地交换。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接