【问题标题】:How to give child class property a different type from the superclass in Dart?如何赋予子类属性与 Dart 中的超类不同的类型?
【发布时间】:2021-11-21 09:08:41
【问题描述】:

我正在使用实体和模型。 基本上,我的实体描述了我的数据应该是什么样子,我的模型扩展了这些实体并具有 toMap 函数将它们转换为 json 对象。

所以我有 2 个实体,Car 和 Brand,其中一个 Car 属性是 Brand 类型。

class Car {
  final String name;
  final Brand brand;

  const Car({
    required this.name,
    required this.brand,
  });
}

class Brand {
  final String label;
  final String color;

  const Brand({
    required this.label,
    required this.color,
  });
}

然后我有 2 个模型 CarModel 和 BrandModel,分别扩展 Car 和 Brand。

class CarModel extends Car {
  CarModel({
    required String name,
    required BrandModel brand,
  }) : super(
          name: name,
          brand: brand,
        );

  Map<String, dynamic> toMap() {
    return {
      'name': name,
      'brand': brand,
    };
  }
}

class BrandModel extends Brand {
  BrandModel({
    required String label,
    required String color,
  }) : super(
          label: label,
          color: color,
        );

  Map<String, dynamic> toMap() {
    return {
      'label': label,
      'color': color,
    };
  }
}

如您所见,在CarModel 中,我希望brand 属性具有BrandModel 类型。 但是,它需要它的超类类型。

所以最后,我的CarModel 中的brand 属性的类型为Brand

我的问题是在 toMap 函数中,我想像这样使用brand.toMap:

  Map<String, dynamic> toMap() {
    return {
      'name': name,
      'brand': brand.toMap(), // <= I want to use toMap() here, so I need brand to be of type BrandModel 
    };
  }

有没有办法强制我的子类对从超类继承的属性具有不同的类型?

【问题讨论】:

    标签: flutter class dart inheritance types


    【解决方案1】:

    有趣的问题。您正在尝试实现继承。因此,当您在 CarModel 的构造函数中提供 required BrandModel brand, 时会发生什么,该构造函数扩展了 Car 具有 final Brand brand; 类型的字段。 BrandBrandModel 对象中获取必要的属性/定义,这是您无法在Map&lt;String, dynamic&gt; toMap() 方法中调用'brand': brand.toMap(), 的唯一原因,因为Brand 类没有此方法。

    Child 具有 Parent 的所有属性/功能/定义,但 Parent 不具备 child 的所有属性。

    解决方案

    因此,您需要将toMap() 放入Brand 类中。这里Abstraction进来了。在这个阶段,你可能不清楚toMap() 方法在体内会有什么,它会映射什么?简单地说,将其声明为abstract。另外,将该类声明为抽象类。 抽象类应该有抽象方法。

    现在,多态进来了。在BrandModel 类中,toMap() 方法将是一个覆盖方法。检查以下测试代码(完整示例)。

    class Car {
      final String name;
      final Brand brand;
    
      const Car({
        required this.name,
        required this.brand,
      });
    }
    
    abstract class Brand {
      final String label;
      final String color;
    
      const Brand({
        required this.label,
        required this.color,
      });
      Map<String, dynamic> toMap();
    }
    
    class CarModel extends Car {
      CarModel({
        required String name,
        required BrandModel brand,
      }) : super(
              name: name,
              brand: brand,
            );
    
      Map<String, dynamic> toMap() {
        return {
          'name': name,
          'brand': brand.toMap(),
        };
      }
    }
    class BrandModel extends Brand {
      BrandModel({
        required String label,
        required String color,
      }) : super(
              label: label,
              color: color,
            );
    
      @override
      Map<String, dynamic> toMap() {
        return {
          'label': label,
          'color': color,
        };
      }
    }
    
    void main() {
      BrandModel brand = BrandModel(label:'Test',color : 'white');
      
      CarModel car = CarModel(name: 'T',brand : brand);
      
      print(car.toMap());
    }
    
    

    【讨论】:

    • 这是一个非常好的答案,我非常喜欢这种方法!但是我还有另一个问题:类 Car 和 Brand 在我的应用程序的表示层中实例化。如果我将这些类抽象化,我将无法再使用它们......想法是在我的域层中拥有实体(汽车和品牌),然后数据层使用扩展这些实体和表示层的模型使用实体,以便表示层与数据层没有任何关系
    • 如果你确定是BrandModel,那么你可以调用'brand': (brand as BrandModel).toMap(),来访问toMap方法
    • 好的,这就是我最终要做的,非常感谢!
    猜你喜欢
    • 2021-03-13
    • 2013-03-08
    • 1970-01-01
    • 2019-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多