是否可以使用Dart执行静态代码?

时间:2014-01-24 17:11:16

标签: static dart factory

Java和Javascript都允许以不同的方式执行静态代码。 Java允许您在类的主体中拥有静态代码,而JS允许您在类定义之外执行静态代码。例子:

爪哇:

public class MyClass {
    private static Map<String,String> someMap = new HashMap<String,String();
    static {
        someMap.put("key1","value");
        someMap.put("key2","value");
        SomeOtherClass.someOtherStaticMethod();
        System.out.println(someMap);
    }
}

JS(基本上是类外的任何JS代码):

var myint = 5;
callSomeMethod();
$(document).ready(function () {
    $("#hiddenelement").hide();
});

然而,似乎Dart支持这两种方式中的任何一种。支持声明全局变量和方法,但调用方法和执行JS中的代码不是。这只能在main()方法中完成。此外,也不允许在类中使用静态代码。

我知道Dart有其他方法可以静态填充Map,就像我的第一个例子一样,但还有另一种情况我可以想到这是必需的。

让我们考虑以下CarRegistry实现,它允许您将汽车模型的字符串映射到相应类的实例。 F.E.当你从JSON数据中获得汽车模型时:

class CarRegistry {
    static Map<String, Function> _factoryMethods = new HashMap<String, Function>();

    static void registerFactory(String key, Car factory()) {
        _factoryMethods[key] = factory;
    }

    static Car createInstance(String key) {
        Function factory = _factoryMethods[key];
        if(factory != null) {
            return factory();
        }
        throw new Exception("Key not found: $key");
    }
}

class TeslaModelS extends Car {

}

class TeslaModelX extends Car {

}

为了能够呼叫CarRegistry.createInstance("teslamodelx");,必须首先注册该课程。在Java中,可以通过向每个Car类添加以下行来完成:static { CarRegistry.registerFactory("teslamodelx" , () => new TeslaModelX()); }。你不想要的是将所有汽车硬编码到注册表中,因为它将失去它作为注册表的功能,并且它增加了耦合。您希望只添加一个新文件即可添加新车。在JS中,您可以在类构造之外调用CarRegistry.registerFactory("teslamodelx" , () => new TeslaModelX());行。

怎么可能在Dart做类似的事情?

即使您允许编辑多个文件来添加新车,如果您编写的库没有main()方法,也是不可能的。唯一的选择然后就是填补Registry.createInstance()方法的第一呼叫的地图,但它不再是一个注册表然后,只是含有汽车的硬编码的列表中选择一个类。

修改:一个小除了最后一条语句我在这里提出:填补这种在createInstance()方法注册的是只有在注册表中我自己的图书馆居住的选项。如果,f.e。我想将自己的类注册到我导入的不同库提供的注册表中,这不再是一个选项。

2 个答案:

答案 0 :(得分:3)

为什么所有关于静电的大惊小怪? 您可以创建一个getter来检查初始化是否已经完成(_factoryMethods != null),如果不这样做并返回映射。

据我所知,这完全取决于代码执行的时间。

我上面展示的方法是延迟初始化 我认为这通常是我猜的首选方式 如果要在加载库时进行初始化 我不知道从init()调用库的main()方法并添加此库init()方法的初始化代码的另一种方法。

以下是关于此主题的讨论executing code at library initialization time

答案 1 :(得分:1)

我在尝试驾驶类似主题的图书馆时遇到了同样的问题。

我的初步尝试探索了使用dart:mirrors迭代库中的类并确定它们是否被这样的注释标记(使用您自己的代码作为示例的一部分):

@car('telsamodelx')
class TelsaModelX extends Car {
}

如果是这样,他们会自动填入注册表。但是,表现并不好,我不确定它是如何扩展的。

我最终采取了更加繁琐的方法:

// Inside of CarRegistry.dart
class CarRegister {
  static bool _registeredAll = false;
  static Car create() {
    if (!_registeredAll) { _registerAll()); }
    /* ... */
  }
}

// Inside of the same library, telsa_model_x.dart
class TelsaModelX extends Car {}

// Inside of the same library, global namespace:
// This method registers all "default" vehicles in the vehicle registery.
_registerAll() {
  register('telsamodelx', () => new TelsaModelX());
}

// Inside of the same library, global namespace:
register(carName, carFxn) { /* ... */ }

在图书馆之外,消费者不得不在某个地方拨打register();来注册他们的车辆。

这是不必要的重复,并且遗憾的是,以一种难以跟踪的方式将注册与课程分开,但使用dart:mirrors.

可能是繁琐的代码或性能损失

YMMV,但随着可注册项目数量的增加,我开始再次关注dart:mirrors方法。