4

依赖倒置原则说(Head First Java):

  • 依赖于抽象。不要依赖具体的类。

继承权是什么意思?作为子类依赖于具体类。

我问的是一个案例 - 有一个接口Bird(没有飞行方法,因为有些鸟不能飞),它代表所有非会飞的鸟。所以我创建了一个类 -NonFlyingBird它实现了Bird.

现在我想为会飞的鸟做一个课程。由于NonFlyingBirdsFlyingBirds具有相同的属性,我扩展了FlyingBirdsfromNonFlyingBirds和 ImplementFlyable以赋予它飞行行为。

难道它不会破坏FlyingBirds从具体类扩展的依赖倒置原则NonFlyingBirds吗?

interface Bird {   // Represents non Flying birds

    void getColor();
    void getHeight();
    ...
 }



class NonFlyingBird implements Bird {
     void getColor();
     void getHeight();
      ...
  }


class FlyingBird extends NonFlyingBird implements Flyable { // Does it break Dependency Inversion principle by extending concrete NonFlyingBird class? 

    Flyable fly;
    ...
  }

注意 - 我扩展的唯一原因是因为它具有与+ 飞行行为FlyingBird相同的属性和方法。NonFlyingBird所以通过继承重用代码是有意义的。

4

3 回答 3

2

简短的回答:没有。

更长的答案:使用策略模式。

依赖于Bird接口的类仍然可以在不知道区别的情况下被传递给一个FlyingBird或实例。NotFlyingBird

的接口Bird仍然相同,或者通常应该是相同的,如果类确实具有不同的接口(FlyingBird您的调用代码所依赖的新方法),那么就有问题了。

也许解决问题的更好方法是使用策略模式。

袖口示例:

public interface Bird {

    void fly();
}

public class BirdImpl implements Bird {

    private FlightStrategy flightStrategy;

    public BirdImpl(FlightStrategy flightStrategy) {

        this.flightStrategy = flightStrategy;
    }

    public void fly() {

        this.flightStrategy.fly();
    }
}

public interface FlightStrategy {

    void fly();
}

public class FlyingBirdFlightStrategy implements FlightStrategy {

    public void fly() {

        System.out.println("Wings flap");
        System.out.println("Wings flap");
        System.out.println("Wings flap");
        System.out.println("Wings flap");
    }
}

public class NonFlyingBirdFlightStrategy implements FlightStrategy {

    public void fly() {

        // do nothing non flying birds can't fly.
    }
}

然后在创建你Bird的使用时,创建默认值BirdImpl并传入FlightStrategy你想要的鸟类型。

于 2019-09-27T05:24:51.397 回答
2

是的,您的直觉是正确的 - 继承在子项与其父项之间引入了不可破坏的编译时和运行时依赖关系。

因此继承的应用是有限的:你应该只使用继承来实现“is”关系,而不是“has code to be shared”关系。但是,您应该小心:仅当对象在整个生命周期中“是”其子类时才继承。Human 可以安全地扩展 Mammal,但是将 Student 定义为 Human 的子类是有风险的。人类可以不再是学生,你不能在运行时改变它。

class FlyingBird extends NonFlyingBird

这是异端邪说!:)

反对“AbstractBird”之类的模板类的运动非常激烈。不幸的是,许多介绍性的编程书籍都教授这种代码共享模式。它本质上没有任何问题,但现在有更好的解决方案——策略、桥牌。在 Java 中,你甚至可以拥有穷人的特质——接口中的默认实现。

在我看来,依赖倒置原则在应用于继承时转化为“优先组合优于继承”。

于 2019-09-27T06:31:08.863 回答
1

尽管我喜欢那里的答案中的策略示例,但我也会回答,因为我认为您对依赖倒置原则有些困惑。

依赖倒置原理的意思

如果您真的不需要 LinkedList 行为,请不要使用它:

public class A {
    private LinkedList<SomeClass> list;
//...
}

改用它:

public class A {
    private List<SomeClass> list; //or even use Collection or Iterable
//...
}

依赖项是我们在类中使用的。

遗产

继承就是我们所说的IS-A关系,与原则无关。如果要让A类继承B类,你需要回答一个问题:A是B是真的吗。如果你问这个问题,你会发现“ FlyingBirdis a NonFlyingBird”这个表达是胡说八道。

通过继承重用代码

想一想:不是所有的鸟都会飞,也不仅仅是鸟(例如苍蝇)会飞。它可能会让我们产生一个想法,即我们应该像您已经完成的那样创建接口 Flyable。然后我们应该重命名NonFlyingBird为 just SimpleBird,因为如果某个生物是鸟,并不意味着它可以飞。最后你会得到:

class FlyingBird extends SimpleBird implements Flyable { 

    void fly() {
        ...
    }
    ...
}

希望它会有所帮助。

于 2019-09-27T08:44:55.400 回答