我正在尝试编写同一程序的两个版本:
我认为它与IDE如何实现正常/调试模式并不完全不同。
我的要求按重要性递减顺序如下:
我理解需求6可能是不可能的,因为需求2需要访问类实现细节(对于公共函数调用另一个公共函数的情况)。
为了便于讨论,请考虑以下高性能版本的程序来讲述一个简单的故事。
class StoryTeller{
void tellBeginning() => print('This story involves many characters.');
void tellMiddle() => print('After a while, the plot thickens.');
void tellEnd() => print('The characters resolve their issues.');
void tellStory(){
tellBeginning();
tellMiddle();
tellEnd();
}
}
使用镜像的简单实现,如下所示:
class Wrapper{
_wrap(Function f, Symbol s){
var name = MirrorSystem.getName(s);
print('Entering $name');
var result = f();
print('Leaving $name');
return result;
}
}
@proxy
class StoryTellerProxy extends Wrapper implements StoryTeller{
final InstanceMirror mirror;
StoryTellerProxy(StoryTeller storyTeller): mirror = reflect(storyTeller);
@override
noSuchMethod(Invocation invocation) =>
_wrap(() => mirror.delegate(invocation), invocation.memberName);
}
我喜欢这个解决方案的优雅,因为我可以改变高性能版本的界面,这才有效。不幸的是,它无法满足要求2,因为tellStory()的内部调用没有被包装。
存在一个简单但更详细的解决方案:
class StoryTellerVerbose extends StoryTeller with Wrapper{
void tellBeginning() => _wrap(() => super.tellBeginning(), #tellBeginning);
void tellMiddle() => _wrap(() => super.tellMiddle(), #tellMiddle);
void tellEnd() => _wrap(() => super.tellEnd(), #tellEnd);
void tellStory() => _wrap(() => super.tellStory(), #tellStory);
}
这个代码可以很容易地使用镜像自动生成,但是它可能会导致代码库大小的大幅增加,特别是如果性能版本具有广泛的类层次结构并且我想要一个const类似于const变量在类树深处的类。
此外,如果任何类没有公共构造函数,这种方法可以防止包的分离(我认为)。
我还考虑用wrap方法包装基类的所有方法,性能版本具有简单的包装函数。但是,我担心这会对性能版本的性能产生负面影响,特别是如果wrap方法要求将调用作为输入。我也不喜欢这个内在地将我的高性能版本链接到慢速版本的事实。在我看来,我认为必须有一种方法可以使较慢的版本成为性能版本的扩展,而不是两个版本都是一些更通用的超级版本的扩展。
我错过了一些非常明显的东西吗?是否有内置的'anySuchMethod'或其他一些?我希望将代理解决方案的优雅与详细解决方案的完整性结合起来。
答案 0 :(得分:1)
您可以尝试将其他调试代码放在asserts(...)中。未在选中模式下运行时会自动删除。另见
否则只需创建一个全局常量(const bool isSlow = true/false;
)在任何地方使用接口和工厂构造函数,它们根据isSlow
值返回接口的慢速或快速实现。
慢速版本可以扩展快速版本以重用其功能,并通过覆盖其方法来扩展它
这样您就不必使用导致代码膨胀的镜像,至少对于客户端代码而言
构建时,所有不必要的代码都会被树木抖动删除,具体取决于isSlow
的设置。
使用依赖注入有助于简化这种开发不同实现的方式。