如何用接口隔离原则实现多态?

How to achieve polymorphism with the Interface Segregation Principle?

我的目标是理解接口隔离原则,同时实现多态。

我的预期结果:我可以用接口隔离原则实现多态

我的实际结果:不,我不能。我被迫创建样板并使用 Liskov 替换原则(如果有一个 Worker,则必须有一个不能吃的 Worker,因此为可以吃的 Worker 创建一个扩展 Worker 的接口)。我想我误解了接口隔离原则。

这是违反接口隔离原则的代码。

public interface IWorker {
  void work();
  void eat();
}

class Human implements IWorker {
  public void work() {
    System.out.println("Human is working.");
  }

  public void eat() {
    System.out.println("Human is eating.");
  }
}

class Robot implements IWorker {
  public void work() {
    System.out.println("Robot is working.");
  }

  public void eat() {
    throw new UnsupportedOperationException("Robot cannot eat");
  }
}

我被告知将界面分成 2 个。

public interface IEatable {
  void eat();
}

interface IWorkable {
  void work();
}

class Human implements IWorkable, IEatable {
  public void work() {
    System.out.println("Human is working.");
  }

  public void eat() {
    System.out.println("Human is eating.");
  }
}

class Robot implements IWorkable {
  public void work() {
    System.out.println("Robot is working.");
  }
}

解决方案是使用 Liskov 替换原则。

public interface IWorkable {
  void work();
}

interface IEatable {
  void eat();
}

interface IWorker extends IWorkable {
}

interface IHumanWorker extends IWorker, IEatable {
}

我建议为此使用抽象 类 而不是接口。如果您需要每个 Workable 都起作用,那么您可以将方法抽象化。如果他们吃东西只是可选的,那么你就不会。一个例子是:

abstract class Workable {

    protected String name;

    public Workable(String name) {
        this.name = name;
    }

    protected abstract void work();

    public void eat() {
        System.err.println("\"" + name + "\" can't eat");
    }
}

class Human extends Workable {
    public Human(String name) {
        super(name);
    }
    @Override
    public void work() {
        System.out.println("Human " + name + " is working!");
    }

    @Override
    public void eat() {
        System.out.println("Human " + name + " is eating!");
    }
}

class Robot extends Workable {
    public Robot(String name) {
        super(name);
    }

    public void work() {
        System.out.println("Robot " + name + " is working!");
    }
}


public class Test {
    public static void main(String[] args) {
        Workable[] workers = new Workable[] {
                new Human("Jerry"),
                new Robot("XAE12")
        };
        for (Workable worker : workers) {
            worker.work();
            worker.eat();
        }
    }
}

我不确定我是否正确理解了你的问题,如果对你有帮助请告诉我。

你的第二步看起来不错,你将界面拆分为两个更具体的界面。机器人“吃”是没有意义的。 (第三步我真的不懂)

在调用方,您现在可以使用您的抽象:

//Polymorphism
List<IWorkable> workers = Arrays.asList(new Robot(), new Human());
//do some work

List<IEatable> eaters = Arrays.asList(new Human(), new Human());
//send for lunch break

如果你想在同一件事上同时拥有这两种行为,那么你的 abstraction/design 似乎是错误的,因为根据定义机器人不能吃东西(由未实现方法的代码味道表示)。

机器人不是 IWorker(你的第一个代码),因为它没有完全填充(完整)契约(接口,吃方法),无论它看起来多么相似。