Как добиться полиморфизма с помощью принципа разделения интерфейсов?
Моя цель - понять принцип разделения интерфейсов и одновременно добиться полиморфизма.
Мой ожидаемый результат: я могу добиться полиморфизма с помощью принципа разделения интерфейсов.
Мой фактический результат: Нет, не могу. Я вынужден создать шаблон и использовать принцип замещения Лискова (если есть рабочий, должен быть рабочий, который не может есть, поэтому создайте интерфейс для рабочего, который может есть, который расширяет 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.");
}
}
Решение состоит в использовании принципа замещения Лискова.
public interface IWorkable {
void work();
}
interface IEatable {
void eat();
}
interface IWorker extends IWorkable {
}
interface IHumanWorker extends IWorker, IEatable {
}
2 ответа
Ваш второй шаг выглядит хорошо, вы разделили интерфейс на два более конкретных интерфейса. Роботу нет смысла «есть». (Я действительно не понимаю третьего шага)
На стороне вызывающего теперь вы можете работать со своими абстракциями:
//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
Если вы хотите иметь оба поведения в одном и том же, то ваша абстракция / дизайн кажется неправильным, поскольку роботы не могут есть по определению (на что указывает запах кода нереализованных методов).
Робот - это не IWorker (ваш первый код), потому что он не полностью заполняет (полный) контракт (интерфейс, метод еды), каким бы похожим он ни казался.
Я бы порекомендовал использовать абстрактные классы вместо интерфейсов. Если вам нужно каждое
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();
}
}
}
Я не уверен, правильно ли я понял ваш вопрос, поэтому, пожалуйста, дайте мне знать, помогло ли это вам.