Dart模式替换静态继承

Mic*_*ick 7 design-patterns dart

在Dart中,不继承静态方法.我主要来自PHP背景,其中静态方法继承不仅可行,而且由于selfstatic关键字非常容易.在编写Dart应用程序时,我一直发现自己遇到了这种情况,我的第一个想法是"我需要为这些其他类可以继承的类添加一个静态方法".

一个例子是一组类,我希望能够调用这些类Foo.getDataById(id)Foo从存储在id下的数据库中的数据创建一个对象id.因为我的每个类都以相同的方式存储在数据库中,所以我觉得应该继承这个功能,这样我就不必在我存储在数据库中的每个类中复制和粘贴实现.同时,这是一种不依赖于类的特定实例的方法(事实上,如果没有实际实例化类的话,你不必考虑你想要获取数据的情况. ),这是一个静态的方法.这是我击中Dart墙的地方,无法继承静态方法,我不知道该怎么做.

有哪些其他设计模式可以允许与静态继承相同的最终结果(即能够在多个类中重用代码而不必在严格需要时创建类的新实例)Dart将支持?有没有惯用的Dart方式来做到这一点?

编辑:虽然我在上面的例子中使用了一些用于构造实例的东西,但并不是我遇到的所有情况都与构造有关.也就是说,对于那些做过的人,我和工厂建设者一起玩了一段时间,但是我还没能让他们在我遇到过的情况下工作.一个问题是,如果我正在进行异步工作,我最终需要为对象返回Future,但我不能在构造函数(afaik)中执行此操作.除此之外,我也很难在超类中编写工厂构造函数,因为它需要访问目标类中的静态字段,但是没有像PHP的static关键字那样,我不能这样做.我可以将它们注入到构造函数的调用中,但是我仍然需要在每个类中定义静态字段(不是那么糟糕)但是甚至无法定义它们可以继承的公共接口(这很糟糕) .

编辑2:我被要求提供一些我想要完成的具体例子.假设我正在制作一款可以购买不同类型升级的游戏,每次升级都可以多次购买.在这里,我会让每个升级键入自己的类,有一些常见的接口来定义类似的方法isActive()apply()或什么的.以及像这样的属性cost.现在,假设我希望每次升级的成本都是该类型的基本成本和已经拥有的该类型的活动升级数量的函数(因此购买时它们会变得更加昂贵).我想要这样做的getCost(numberOfPurchasedUpgrades)方法是向超类添加静态方法,以便我可以定义确定升级成本的标准函数.如果升级不遵循默认价格进展,则可以通过特定升级类型覆盖此静态方法.这种方法在静态上下文中也是有意义的,因为我经常需要能够获得一种升级的代价而不需要实际需要该升级类型的实例.但是,如果没有静态继承,我将不得不使该getCost方法非静态,这意味着它需要被调用new UpgradeType1().getCost(countOfUpgradeType1),或者我需要getCost在每个升级类中定义相同的静态方法.前者创建不需要的实例并且被抛弃,后者没有做任何事情来强制getCost升级方法的存在(意味着我不能指望它在那里,哪种方式破坏多态)和需要我复制并粘贴相同的逻辑多个地方.我可以通过使它成为顶级函数来解决复制和粘贴问题,但后来我正在污染全局命名空间,我仍然没有任何强制执行接口.当然有更好的方法来解决这个问题.

另一个例子是在一组对象上创建一些基本的CRUD功能.我想定义一个超类,它可以完成创建表的工作,以显示该类型的现有对象,创建新对象的表单等.没有静态继承意味着我不能这样做,所以我的下一个想要创建一个表构建类来获取传入的对象.但是现在如果我想创建该类型的新对象,我无法引用该类.解决方案是否相同,我需要将更多内容传递给表构建器吗?如果是这样,它在哪里结束?表构建类是否需要一个项目数组,一个创建函数,一个删除函数和一个更新函数都传递给构造函数?

mez*_*oni 6

如果我理解正确,您需要使用以下模式。

abstract class Base {
  Base getById(id);
}

class Foo extends Base {
}
Run Code Online (Sandbox Code Playgroud)

然后。

var foo = Foo.getById(id);
Run Code Online (Sandbox Code Playgroud)

您想将所有内容都分配给模型吗?

这是一种非常原始的方式。静态类在许多情况下不可用。

看看这个样本。这个示例非常简单,但它演示了为什么不需要使用静态类。

import 'package:queries/queries.dart';
import 'package:reflection/reflection.dart';

// Begin user code
class MyDatabase extends Database {
  DbSet<Category> categories;

  DbSet<Product> products;
}

class Category {
  int id;

  String name;

  String toString() => name;
}

class Product {
  Category category;

  int id;

  String name;

  String toString() => name;
}

// End user code

void main() {
  var db = new MyDatabase();
  var odd = db.categories.firstOrDefault((c) => c.name == "Optical disk drives");
  if(odd != null) {
    print("======================");
    print(odd.name);
    print("----------------------");
    var products = db.products.where((p) => p.category == odd);
    for(var product in products) {
      print(product);
    }
  }

  var threeProducts = db.products.orderBy((p) => p.name).take(3);
  print("======================");
  print("Only three products");
  print("----------------------");
  for(var product in threeProducts) {
    print(product);
  }
}

// Internal code

class DbSet<T> extends Enumerable<T> {
  TypeInfo _ti;

  DbSet() {
    _ti = typeInfo(T);
  }

  Iterator<T> get iterator {
    var data = new _Data()._data[T];
    if(data != null) {
      return data.iterator;
    }

    return null;
  }
}

abstract class Database {
  Database() {
    var queryableType = typeInfo(Enumerable);
    var ti = typeInfo(runtimeType);
    var variables = ti.getVariables(BindingFlags.PUBLIC | BindingFlags.INSTANCE
      | BindingFlags.DECLARED_ONLY);
    for(VariableInfo variable in variables.values) {
      if(variable.type.isA(queryableType)) {
        var object = variable.type.newInstance().reflectee;
        variable.setValue(this, object);
      }
    }
  }
}

class _Data {
  static _Data _current;

  Map _data = {};

  factory _Data() {
    if(_current == null) {
      _current = new _Data._internal();
    }

    return _current;
  }

  _Data._internal() {
    _fillData();
  }

  void _fillData() {
    var vga = new Category();
    vga.id = 1;
    vga.name = "Video adapters";
    var odd = new Category();
    odd.id = 2;
    odd.name = "Optical disk drives";
    var categories = [vga, odd];
    var products = [];
    var geforce = new Product();
    geforce.id = 1;
    geforce.category = vga;
    geforce.name = "GeForce GTX650";
    products.add(geforce);
    var radeon = new Product();
    radeon.id = 2;
    radeon.category = vga;
    radeon.name = "Radeon HD7770";
    products.add(radeon);
    var sh224 = new Product();
    sh224.id = 3;
    sh224.category = odd;
    sh224.name = "DVD-RW Samsung SH-224";
    products.add(sh224);
    var dvr221 = new Product();
    dvr221.id = 4;
    dvr221.category = odd;
    dvr221.name = "DVD-RW Pioneer DVR-221";
    products.add(dvr221);
    _data[Category] = categories;
    _data[Product] = products;
  }
}
Run Code Online (Sandbox Code Playgroud)
======================
Optical disk drives
----------------------
DVD-RW Samsung SH-224
DVD-RW Pioneer DVR-221
======================
Only three products
----------------------
DVD-RW Pioneer DVR-221
DVD-RW Samsung SH-224
GeForce GTX650
Run Code Online (Sandbox Code Playgroud)

聚苯乙烯

如果你想要 CRUD,你可以使用数据库(应用)对象。

// Begin user code

class SaleOrder extends DocumentObject {
  Customer customer;
}

class Customer extends CatalogObject {
  String address;
}

class Inventory extends MovementObject {
  Product product;

  double quantity;
}

// End user code

abstract class DbObject {
  dynamic id;
}

abstract class AppliedObject extends DbObject {
  void delete();

  void save();
}

abstract class CatalogObject extends AppliedObject {
  String name;  

  void delete() {
    // delete catalog object
  }

  void save() {
    // save catalog object
  }
}

abstract class DocumentObject extends AppliedObject {
  DateTime date;

  dynamic number;

  void delete() {
    // delete document object
  }

  void save() {
    // save document object
  }
}

abstract class MovementObject extends DbObject {
  DocumentObject owner;

  void write() {
    // write movement object
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 代码摘要将使这个答案更好 (5认同)
  • 对我来说,这个答案并不能解释任何事情。这个问题是理论上的,我认为需要一个理论上的答案,而不仅仅是一堆代码。 (2认同)