【问题标题】:How to have a function in an abstract class return instances of a child classes in typescript如何让抽象类中的函数返回打字稿中子类的实例
【发布时间】:2020-03-01 13:48:15
【问题描述】:

有没有可能有这样的伪代码:

abstract class AbstractParent {
    protected value: number;
    constructor(value: number) {
        this.value = value;
    }
    ...
    public times(multiplicator: number) {
        return new ???(value * multiplicator);
    }
}

哪个为class Foo extends AbstractParent返回一个新的Foo,为class Bar extends AbstractParent返回一个新的Bar

【问题讨论】:

    标签: typescript inheritance abstract-class parent-child extends


    【解决方案1】:

    一种可维护的方法是将times 计算保留在基类中,并在FooBar 内部实现单独的create 工厂方法。这样,基类就不会知道它的扩展子类。

    您在AbstractParent 中将create 声明为abstract,以确保它将在所有子类中实现。 polymorphic this 返回类型确保times 的调用者返回的实例具有相同的子类类型(Playground)。

    abstract class AbstractParent {
        protected value: number;
    
        constructor(value: number) {
            this.value = value;
        }
    
        times(multiplicator: number) {
            return this.create(this.value * multiplicator);
        }
    
        // factory method creates instances of same polymorphic type (Foo / Bar)
        protected abstract create(value: number): this
    }
    
    class Foo extends AbstractParent {
    
        create(value: number) {
            // Polymorphic this type is Foo here, so it's OK to return a Foo.
            // Compiler is not aware of the class context, so we cast. 
            return new Foo(value) as this
        }
    }
    
    class Bar extends AbstractParent {
        // same as Foo
        create(value: number) {
            return new Bar(value) as this
        }
    }
    
    const foo = new Foo(42).times(2) // Foo
    const bar = new Bar(42).times(3) // Bar
    

    【讨论】:

    • 我同意factory method design pattern 是一个不错的选择。但是,我不明白您的实现选择... times 方法应该调用工厂方法。工厂方法应该受到保护。并且工厂方法的实现应该只实例化相应的类(不调用方法次)。
    • 你是对的,将它与之前的替代方案混为一谈。 times 在 OP 的问题中是公开的,因此拥有一个公共基础 times 方法更有意义,该方法在内部调用多态保护工厂方法。更新答案,谢谢!
    • 谢谢。我试过这种方法,现在当我尝试做const foo = new Foo(42).times(2)时我得到TypeError: this.create is not a function
    • @Hade0011 TypeError 是与 TS 无关的 JavaScript 运行时错误。答案中的操场有效,您能提供一个样本吗?听起来更像是您在某处混淆了 this 上下文...
    • @ford04 你完全正确。我修复了我的this,现在它就像一个魅力一样工作。非常感谢!
    【解决方案2】:

    您可以将子类型传递给父构造函数并保存引用。这可以防止父母必须了解所有可能的孩子类型(尽管我同意另一个答案,即可能有更好的方法来实现您的总体目标)。像这样的东西(playground link):

    type ChildConstructor<Child> = new (value: number, childConstructor: ChildConstructor<Child>) => Child;
    
    abstract class AbstractParent<Child extends AbstractParent<Child>> {
        protected value: number;
        protected childConstructor: ChildConstructor<Child>;
    
        constructor(value: number, childConstructor: ChildConstructor<Child>) {
            this.value = value;
            this.childConstructor = childConstructor;
        }
    
        public times(multiplicator: number): Child {
            return new this.childConstructor(this.value * multiplicator, this.childConstructor);
        }
    }
    
    class Foo extends AbstractParent<Foo> {
        constructor(value: number) {
            super(value, Foo);
        }
    }
    
    class Bar extends AbstractParent<Bar> {
        constructor(value: number) {
            super(value, Bar);
        }
    }
    

    请注意,要获得 100% 的类型安全,每个子类都需要至少有一个额外的私有属性或方法,以防止 TypeScript 的“鸭子类型”认为这些类是可互换的(因为它们共享相同的属性和方法)。

    【讨论】:

      猜你喜欢
      • 2019-07-06
      • 1970-01-01
      • 1970-01-01
      • 2015-08-10
      • 2016-10-03
      • 2015-08-13
      • 2021-09-26
      • 1970-01-01
      • 2022-01-12
      相关资源
      最近更新 更多