Java 如何利用接口分离原理实现多态性?

Java 如何利用接口分离原理实现多态性?,java,solid-principles,interface-segregation-principle,Java,Solid Principles,Interface Segregation Principle,我的目标是理解接口隔离原则,同时实现多态性 我的预期结果是:我可以使用接口分离原则实现多态性 public interface IWorker { void work(); void eat(); } class Human implements IWorker { public void work() { System.out.println("Human is working."); } public void eat() { Sy

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

我的预期结果是:我可以使用接口分离原则实现多态性

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");
  }
}
public interface IWorkable {
  void work();
}

interface IEatable {
  void eat();
}

interface IWorker extends IWorkable {
}

interface IHumanWorker extends IWorker, IEatable {
}
我的实际结果是:不,我不能。我被迫创建样板文件并使用Liskov替换原则(如果有工人,必须有不能吃的工人,所以为可以吃的工人创建一个扩展工人的接口)。我想我误解了接口隔离原则

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");
  }
}
public interface IWorkable {
  void work();
}

interface IEatable {
  void eat();
}

interface IWorker extends IWorkable {
}

interface IHumanWorker extends IWorker, IEatable {
}
这是违反接口隔离原则的代码

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");
  }
}
public interface IWorkable {
  void work();
}

interface IEatable {
  void eat();
}

interface IWorker extends IWorkable {
}

interface IHumanWorker extends IWorker, IEatable {
}
我被告知将接口分成两部分

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 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");
  }
}
public interface IWorkable {
  void work();
}

interface IEatable {
  void eat();
}

interface IWorker extends IWorkable {
}

interface IHumanWorker extends IWorker, IEatable {
}

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

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
//多态性
List workers=Arrays.asList(新机器人(),新人类());
//做些工作
List-eaters=Arrays.asList(new-Human(),new-Human());
//派人去吃午饭
如果你想在同一件事情上同时拥有两种行为,那么你的抽象/设计似乎是错误的,因为机器人不能根据定义进食(由未实现方法的代码气味指示)


机器人不是IWorker(你的第一个代码),因为它不能完全满足(完整的)合同(接口、eat方法),不管它看起来有多相似。

我不太明白你的问题是什么。使用IWorkable作为一个函数参数已经让我们使用多态性我认为这与Liskov替换原理相反?机器人不应该有吃法。还是LSP真的建议这样做?我喜欢在抽象类中假设方法错误的想法,因此您必须在每个新客户机上重写该方法。这就是robot没有eat方法的原因。我刚刚意识到我忘了发布输出,我会在再次使用电脑时编辑它。如果愿意,也可以在原始方法中抛出异常,重要的是不要重写robot类中的eat方法。我明白了,您可以在尽可能低的级别上使用接口(无需创建IWorker或IHumanWorker)。这就是我要找的,第一个代码不是问题。