设计模式自动化

时间:2017-11-30 16:41

软件开发项目正在变得日趋庞大与复杂。越是复杂的项目,其软件开发与维护的成本越有可能远远超过花费在硬件上的成本。

软件的规模与其开发和维护的成本之间存在着一种超线性的关系。说到底,庞大且复杂的软件需要优秀的工程师进行开发与维护,而优秀的工程师总是难以吸引的,留住他们的代价也更高昂。

尽管维护每行代码的成本如此高昂,但我们依然编写了大量的样板代码,而这其中有很大一部分可以由更智能的编译器来替代完成。实际上,多数模板代码只是重复地实现设计模式,而其中一部分模式已被理解得十分透彻,只要我们教会编译器一些技巧,它们完全是可以自动实现的。

实现观察者模式

相关厂商内容

百度AI技能渠道体系首席研究员的重构分享 分还是合?58到家订单中心架构演进 架构优化!爱奇艺面对流量洪峰的三板斧 摩拜单车:如何通过机器学习等技术提高单车运营效率 聚合物联网、人工智能、DevOps等热门课程,【华为云】免费上云实践

相关赞助商

设计模式自动化

以观察者模式作为例子。这个模式在1995年就已被早早地提出了,并且成为了Model-View-Controller架构成功实现的基础。组成这个模式的各元素在首个版本的Java(1995,Observable接口)和.NET(2001,INotifyPropertyChanged接口)中都得到了实现。虽然这些接口都是框架中的一部分,但还是需要开发者的手动实现。

INotifyPropertyChanged接口仅包含一个名叫PropertyChanged的事件,当对象的任何一个属性值发生变化时,都需要触发该事件。

让我们来看一看一个简单的.NET示例:

public Person : INotifyPropertyChanged { string firstName, lastName; public event NotifyPropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { if ( this.PropertyChanged != null ) { this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } public string FirstName { get { return this.firstName; } set { this.firstName = value; this.OnPropertyChanged(“FirstName”); this.OnPropertyChanged(“FullName”); } public string LastName { get { return this.lastName; } set { this.lastName = value; this.OnPropertyChanged(“LastName”); this.OnPropertyChanged(“FullName”); } public string FullName { get { return string.Format( “{0} {1}“, this.firstName, this.lastName); }}}

属性最终依赖于一组字段,一旦我们改变一个字段,那我们就要为一个相关联的属性触发PropertyChanged事件。

难道编译器不能为我们自动完成这一工作吗?完整的答案是:如果我们考虑到所有可能发生的边界情况,那么要检测字段与属性之间的依赖确实是一项令人望而生畏的任务。因为属性所依赖的字段有可能指向其它对象,这些对象可以调用其它方法。更糟的是,它们还可能调用虚方法或delegate,而编译器却无法确定具体的类型。因此对这个问题来说,如果我们不希望编译时间达到几小时或几天,而是可以在几秒或几分钟内就完成的话,那确实不存在一个通用的解决方案。不过,在真实场景中,编译器是可以理解大多数简单的属性的。因此简短的回答是:是的,在典型的应用中,编译器可以为超过90%的属性生成通知代码。

在实践中,同样的类可以由以下方式实现:

[NotifyPropertyChanged] public Person { public string FirstName { get; set; } public string LastName { get; set; } public string FullName { get { return string.Format( “{0} {1}“, this.FirstName, this.LastName); }} }

这段代码告诉了编译器要做什么(实现INotifyPropertyChanged),而不是该怎样做。

样板代码是一种反模式

观察者(INotifyPropertyChanged)模式仅是在大型应用程序中产生大量样板代码的一个例子,而在典型的代码库中经常充斥着实现各种模式的大量样板代码。即使它们并不总是被认可为“官方的”设计模式,但它们依然是模式,因为它们在代码库中经常重复不断地出现。最常见的代码重复的原因包括:

追踪、日志

前置条件与不变式的检测

授权与审计

锁定与线程分配

缓存

跟踪变化(以实现撤消/重做)

事务处理

异常处理

这些特性难以用寻常的面向对象技术进行封装,这也是造成了它们经常用样板式代码实现的原因。这真的是一件那么糟糕的事吗?

确实是。

使用样板代码解决横切关注点(cross-cutting concerns),会最终导致其违反优秀软件工程应遵守的基本原则:

当一个单一属性的setter方法中的实现囊括了多个关注点的内容,如验证、安全、INotifyPropertyChanged及撤消/重做时,单一职责原则即被违反。

能够在不修改现有代码的情况下加入新的特性,才是最好地实现了开闭原则,该原则指出,软件实体应该对扩展开放,而对修改关闭。

不要重复你自己(DRY)原则不能容忍因手工实现设计模式所带来的代码重复。