我正在寻找在Dart超类中编写一个函数,该函数根据实际使用它的子类采取不同的操作.像这样的东西:
class Foo {
Foo getAnother(Foo foo) {
var fooType = //some code here to extract fooType from foo;
switch (fooType) {
case //something about bar here:
return new Bar();
case //something about baz here:
return new Baz();
}
}
}
class Bar extends Foo {}
class Baz extends Foo {}
Run Code Online (Sandbox Code Playgroud)
其中的想法是我有一些对象,并希望获得同一(子)类的新对象.
主要问题是应该是什么类型fooType
?我的第一个想法是Symbol,这导致了简单的案例陈述case #Bar:
,但我不知道如何填充fooType
符号.我能想到的唯一选择是做类似的事情,Symbol fooType = new Symbol(foo.runtimeType.toString());
但我的理解是runtimeType.toString()
转换为javascript后无效.您可以通过使用Mirrors来解决这个问题,但这应该是一个轻量级的库,所以这些不在桌面上.Object.runtimeType
返回Type
类的东西,但我不知道如何创建Type
我可以用于case语句的实例.也许我错过了一些更适合这个的Dart库?
在Dart中,不继承静态方法.我主要来自PHP背景,其中静态方法继承不仅可行,而且由于self
和static
关键字非常容易.在编写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功能.我想定义一个超类,它可以完成创建表的工作,以显示该类型的现有对象,创建新对象的表单等.没有静态继承意味着我不能这样做,所以我的下一个想要创建一个表构建类来获取传入的对象.但是现在如果我想创建该类型的新对象,我无法引用该类.解决方案是否相同,我需要将更多内容传递给表构建器吗?如果是这样,它在哪里结束?表构建类是否需要一个项目数组,一个创建函数,一个删除函数和一个更新函数都传递给构造函数?
几次,我遇到了一个用例,我需要为类本身的构造定义一个接口.一个这样的例子可能是,如果我想创建一个接口类,它定义了对象可以通过它自己序列化和反序列化的接口(用于输入到数据库,作为JSON发送等).你可能写这样的东西:
abstract class Serializable {
String serialize();
Serializable unserialize(String serializedString);
}
Run Code Online (Sandbox Code Playgroud)
但是现在你有一个问题,正如serialize()
一个实例方法,unserialize()
应该是一个静态方法(不可由Interface继承或强制执行)或构造函数(也不可继承).
这留下了一个状态,其中Serializable
需要用于定义接口的类来定义serialize()
方法,但是没有办法要求这些类定义static unserialize()
方法或Foo.fromSerializedString()
构造函数.
如果您创建unserialize()
实例方法,那么反序列化实现类Foo
将如下所示:
Foo foo = new Foo();
foo = foo.unserialize(serializedString);
Run Code Online (Sandbox Code Playgroud)
这是相当繁琐和丑陋的.
我能想到的唯一另一个选择是在Serializable
接口中添加一个注释,要求很好地实现类定义适当的静态方法或构造函数,但如果开发人员错过它并且还会损害代码完成,这显然很容易出错.
那么,有更好的方法吗?是否存在一些模式,您可以通过这种模式强制实现类来定义构建自身的方法,或者提供一般效果的方法?
我正在尝试为我的Dart服务器应用程序编写一些测试,并且我一直在使用HttpClient类(以及相关的HttpClientRequest和HttpClientResponse类来向服务器发出测试请求(注意我正在使用这些类,因为我需要dart:io包来运行服务器,所以我也不能导入dart:html).到目前为止,这一直进展顺利,我已经能够编写测试来检查服务器是否正在返回响应正确的HTTP状态代码.我用来进行这些测试调用的代码基础如下:
Future<HttpClientResponse> makeServerRequest(String method, Uri uri, [String jsonData]) async {
HttpClient client = new HttpClient();
HttpClientRequest request = await client.openUrl(method, uri);
request.write(jsonData);
return request.close();
}
Run Code Online (Sandbox Code Playgroud)
现在我需要编写一个测试,确保响应的主体,而不仅仅是状态代码,是正确的.问题是我似乎无法找到任何允许我实际访问HttpClient*类中的响应主体的东西.到目前为止我能找到的最接近的是HttpClientResponse.contentLength属性,但这只能告诉我响应体有多大,而不是实际内容.
如何从这些请求中检索响应正文?或者,如果您不能,是否有其他方式我可以在服务器端应用程序上发出请求,以便我可以阅读响应?
请考虑以下代码
import 'dart:async';
Future main() async {
try {
print("trying");
await doSomething();
print("success");
} catch (e) {
print("caught");
}
}
Future<int> doSomething() async {
await doSomethingElse();
return 5;
}
Future<int> doSomethingElse() async {
throw new Exception();
}
Run Code Online (Sandbox Code Playgroud)
运行时,抛出的异常会被doSomethingElse()
捕获main()
,并且一切都按预期工作.但是,编写该doSomething()
方法的人并没有意识到这doSomethingElse()
是异步的,而是编写了跟随(注意缺失await
).
Future<int> doSomething() async {
doSomethingElse();
return 5;
}
Run Code Online (Sandbox Code Playgroud)
现在没有发现异常.相反,输出现在看起来像这样:
trying
success
Unhandled exception:
Uncaught Error: Exception
Stack Trace:
#0 doSomethingElse.<doSomethingElse_async_body> (file:///C:/code/test.dart:19:7)
#1 Future.Future.<anonymous closure> (dart:async/future.dart:118)
<snip>
Run Code Online (Sandbox Code Playgroud)
发生的事情是doSomething()
立即返回,然后在另一个上下文中,doSomethingElse()
抛出错误,立即停止所有执行.我知道对此的答案可能是"嗯,不要那样做." 但是我正在考虑我可能无法控制我正在调用的方法的情况(比如说它们是否是库的一部分). …
首先,我正在做的事情的背景.我正在运行一个处理HttpRequests的HttpServer.
HttpServer.bind(ADDRESS, PORT).then((HttpServer server) {
listenSubscription = server.listen(onRequest);
});
void onRequest(HttpRequest request) {
//handle request here
}
Run Code Online (Sandbox Code Playgroud)
我想为所有这些添加一些日志记录,并且由于它的异步性质,想要为请求添加一些识别标记(因此我可以将请求收据与响应匹配,例如).里面的代码onRequest()
调用一堆其他函数来做不同的事情(处理GET和POST请求等),所以简单地在顶部生成一个id是一个麻烦的解决方案,因为我必须通过所有其他的传递它函数调用.然而,我已经在HttpRequest
对象周围传递,所以我认为在它上面抛出一个id
字段会很好,就像在Javascript中一样,除了Dart不能那样工作.
然后想到了继承HttpRequest
类HttpRequest
的onRequest()
方法,但转换方法接收的对象似乎比我需要的更麻烦和开销.
所以我问,是否有任何惯用的Dart方法将一些数据附加到现有对象?如果没有惯用的东西,那么你能想到的最简单的(代码和运行时复杂性)方法是什么?
Dart的Datetime类有许多命名构造函数,但DateTime.parse()
不是其中之一.相反,DateTime.parse()
是一个返回DateTime的静态方法.对我来说,它作为构造函数是有意义的(因为您以与Datetime.utc()
构造函数没有太大不同的方式生成新的DateTime对象).
我提出的理论是反映int.parse
不是构造函数或允许更容易链接的事实(您不需要使用静态方法的级联运算符).但也许还有另一个原因,我没想到.有谁知道为什么他们没有使它成为命名构造函数?
我花了大部分时间试图找到答案,但似乎没有一个在那里.我需要在表中创建一行的函数,从插入的行中检索自动增量,然后使用该值在第二个表中插入另一行.功能类似于以下php的东西:
$mysql_query("INSERT INTO table1 SET columns='values'");
$id = mysql_insert_id();
$mysql_query("INSERT INTO table2 SET id='$id', columns='values'");
Run Code Online (Sandbox Code Playgroud)
我遇到的问题是,在我的应用程序中,所有类之间共享一个MySQL连接,所以我担心这可能会导致竞争条件,其中另一个类在运行第一行和第二行之间插入一行上面提到的.
我能提出的最简单的解决方案是使用任何mysql_insert_id()
开放新的,唯一的连接的功能,但这似乎是一个巨大的不必要的开销.我玩过的其他答案包括插入一个唯一值(可能是UUID()
用它创建)并使用它而不是自动增量值,或者可能将第一个插入和调用LAST_INSERT_ID()
放入存储函数中(尽管我不确定)如果那样可以解决可能的竞争条件).
我也一直在调查交易,看看它们是否有帮助,但几乎没有关于如何mysql_insert_id()
与它们进行精确交互的文档.我能说的最好,他们可能在这里没有帮助,因为另一个INSERT
与任何事务的锁没有冲突的人仍然可以执行并可能导致相同的竞争条件.
所以,假设我没有与上述任何一个错误(如果我是,请纠正我),确保100%第二个INSERT
使用正确值的最佳方法是什么?
我正在努力熟悉聚合物,并一直在尝试用它构建一个示例应用程序.按照https://www.dartlang.org/docs/tutorials/polymer-intro上的教程并阅读其他StackOverflow问题,例如如何从Polymer Dart触发自定义事件?我设法构建了两个元素,其中一个元素触发第二个元素所作用的事件.但是,我只能弄清楚如何在触发元素的子元素的情况下执行此操作.例如,如下
foo.html
<link rel="import" href="bar.html">
<polymer-element name="foo">
<template>
<my-bar on-myevent="{{react}}"></mybar>
</template>
<script type="application/dart" src="foo.dart"></script>
</polymer-element>
Run Code Online (Sandbox Code Playgroud)
foo.dart
@CustomTag('my-foo')
class Foo extends PolymerElement {
Foo() {}
Foo.created() : super.created();
void react() {
print("Event happened and was heard!");
}
}
Run Code Online (Sandbox Code Playgroud)
一个bar.html
<polymer-element name="bar">
<template>
<button on-click="{{click}}"></button>
</template>
<script type="application/dart" src="bar.dart"></script>
</polymer-element>
Run Code Online (Sandbox Code Playgroud)
bar.dart
@CustomTag('my-bar')
class Bar extends PolymerElement {
Bar() {}
Bar.created() : super.created();
void click(Event e, var details, Node node) {
print("Triggering event");
fire('my-event');
}
}
Run Code Online (Sandbox Code Playgroud)
的index.html
<!DOCTYPE …
Run Code Online (Sandbox Code Playgroud) 我已经构建了一些返回产品目录部分的ajax,我正在尝试将xml输出到文档中,到目前为止,这就是我所拥有的:
$("#catalog").append("<table><tr><th></th><th>Item Name</th><th>Price</th><th>Description</th></tr>");
$(data).find("item").each(function() {
$("#catalog").append("<tr>"+
"<td style='valign:top'><img src='"+$(this).find("["link").text()+"' /></td>"+
"<td>"+$(this).find("title").text()+"</td>"+
"<td>"+$(this).find("price").text()+"</td>"+
"<td style='valign:top'>"+$(this).find("description").text()+"</td>"+
"</tr>"
);
});
$("#catalog").append("</table>");
Run Code Online (Sandbox Code Playgroud)
我希望这会将表的开头写入文档,然后是每个数据行,最后是</ table>.相反,当我在页面上查看源代码时,我得到了这个......
<div id="catalog">
<table>
<tr>
<th></th>
<th>Item Name</th>
<th>Price</th>
<th>Description</th>
</tr>
</table>
<tr>
<td style="valign:top"><img src="http://image1.jpg"></td>
<td>Item1</td>
<td>Price1</td>
<td style="valign:top">Description1</td>
</tr>
<tr>
<td style="valign:top"><img src="http://image2.jpg"></td>
<td>Item2</td>
<td>Price2</td>
<td style="valign:top">Description2</td>
</tr>
<tr>
<td style="valign:top"><img src="http://image3.jpg"></td>
<td>Item3</td>
<td>Price3</td>
<td style="valign:top">Description3</td>
</tr>
</div>
Run Code Online (Sandbox Code Playgroud)
注意在表结束后如何添加数据,即使.append("</ table>")行是在.each()之后.
这使我相信代码没有按顺序执行,而.each()函数正在演示一些并发性.这让我感到困惑,因为jquery api没有提到回调,所以我发现自己在究竟发生了什么以及我应该做些什么来让它正确显示时有点不知所措.任何帮助将非常感激.
dart ×8
asynchronous ×1
dart-polymer ×1
each ×1
jquery ×1
lastinsertid ×1
mysql ×1
php ×1
polymer ×1
sql ×1
transactions ×1