抽象 class 是否应该直接实现接口。有什么优点和缺点

Should an abstract class implement interfaces directly. What are the advantages and disadvantages

我正在研究抽象的一些概念,想知道抽象 class 是否应该直接实现接口,或者您应该扩展 class 并在子类型中实现接口。

所以在下面的例子中:

interface Being{
    alive:boolean;
}

abstract class Animal implements Being{
    alive:boolean;
}

class Dog extends Animal{
    bark(){
        console.log("Bark");
    }
}

class Earth{
    beings:Being[];
}

示例可以重写如下所示:

interface Being{
    alive:boolean;
}

abstract class Animal{
    alive:boolean;
}

class Dog extends Animal implements Being{
    bark(){
        console.log("Bark");
    }
}

class Earth{
    beings:Being[];
}

我的问题是:

  1. 第二个例子更好吗?
  2. 我们需要更高版本的示例是什么?
  3. 高版本有什么优势?

你可以走得更远,你根本不需要实现接口,因为 typescript 使用结构兼容性来确定类型兼容性。例如这个编译:

interface Being {
    alive: boolean;
}

abstract class Animal {
    alive: boolean = true;
}

class Dog extends Animal {
    bark() {
        console.log("Bark");
    }
}

class Earth {
    beings: Being[] = [new Dog()]
}

显式实现接口的优点是您会在 class 声明位置得到错误,而不是仅在 class 使用位置得到错误。

关于您问题的主要部分,您应该将 implements 放在实际执行的 class 上。如果 abstract class 实现接口的所有成员,最好将 implements 放在那里。如果你的抽象class没有实现所有的方法,而你期望一些派生的classes不需要实现接口,那么把implements放在具体的class上需要实现接口的es.

好吧,我想你已经给了自己答案。这两个示例代表不同的用例,所以我认为没有 "better example".

让我们试着把它分解成简单的单词。

第一个例子,你有一个存在,所有动物都明确地具有属性 "alive"。在此示例中,这也适用于 Dog。

然而,在第二个示例中,您的 Animal 不需要具有 "alive" 属性。 (那么问题是,拥有它是否真的有意义)。然而 Dog 再次实现了接口。

所以如果你说有可能有一只狗,那是一只动物但不应该有属性 "alive"(也许是 Zombie-Dog)你应该把它放在狗身上本身。但是如果你打算将所有 fields/functions/logic 实现到 Animal class 中(并且你不关心 Zombie-Dogs)你应该把接口放在 Animal class.

所以这可能不是您正在寻找的 "clear" 答案。但这要视情况而定。您应该始终在相应逻辑所在的位置实现接口。所以如果你想让活着的逻辑在动物身上,把它放在那里,如果可以有没有活着的动物属性,把它放在狗身上。