论道WP(三):应用程序栏
作者通过具体翔实的例子介绍了Winodws Phone 7中应用程序栏的使用方式。
该内容已经被标记书签!
标记书签错误,请重试!
![]()
作者 Mark Seemann 译者 李永伦 发布于 2011年12月29日
我在写《Dependency Injection in .NET》时经常碰到的一个反应是“你怎么把依赖注入写成一整本书?”这种难以置信的反应是很自然的,如果你觉得依赖注入的主要模式(构造函数注入)非常容易理解。
虽然这个主要模式易于理解,却很难成功实现依赖注入,因为这个机制只是一个更大的上下文里的一部分。DI是对控制反转(IoC)原则的应用,想要成功实现IoC,你就要把你的思维逆转过来。这篇文章勾画了成功实现DI所需的心智模型。
如果你不理解DI的目的,就很容易把它实现错。这是我最近看到的一个例子:
private readonly ILog log;
public MyConsumer(ILog log)
{
this.log = log ?? LogManager.GetLogger("My");
}
从封装的角度来看,这个方案的主要问题是MyConsumer类好像无法确定它是否对日志程序这个依赖的创建拥有控制权。虽然这个示例很简单,但如果LogManager返回的ILog实例包装了一个非托管资源,需要在不使用的时候释放掉,那就有可能演变成一个问题。
这样的实现之所以会出现,是因为开发者把全部精力放在让MyConsumer可以进行单元测试。这样做的理由是开发者只想在单元测试的时候可以替换ILog,其它情况应该使用LogManager返回的实例。
这实际上就是Bastard Injection反模式。其中一个潜在问题是它很容易违反里氏代换原则,因为某个特定的实现得到了特殊对待。
DI(Dependency Injection,依赖注入)的目的比起单纯地协助进行单元测试要广泛的多。它的目的是实现松散耦合,以便提升整个解决方案的可维护性。(如果你想知道为什么松散耦合能够增加可维护性,我的书的第一章讨论了这个话题,你可以免费下载试读。)
松散耦合可被概述为基于接口而不是具体实现进行编程的思想。但是,因为接口没有构造函数,如何创建那些接口的实例马上就成了一个问题。
根据你的编程方式,有两种完全不同的方案可以获取接口的实例:

对于前面的示例,很容易就会演变成服务定位器(Service Locator)反模式,像这样:
public MyConsumer()
{
this.log = Locator.Resolve<ILog>();
}
除了服务定位器的其它问题,这种方案的问题还在于LogManager.GetLogger("My")方法调用所需的参数丢失了。假设其它consumer对象需要的日志程序是通过不同的参数实例化的,那么这个版本的服务定位器就无法工作了。
这通常会导致定位器的Resolve方法有一个或多个重载版本,以便向服务定位器提供上下文信息。这样,离违反里氏代换原则就不远了。
DI提供了一个更好的方案:
private readonly ILog log;public MyConsumer(ILog log)
{
if (log == null)
throw new ArgumentNullException("log");
this.log = log;
}
这是控制反转的纯粹形式。ILog的任何实现都能接受,同时通过条件语句保证这个实例不为null。这跟使用服务定位器相反,上下文没有在构建对象图的时候丢失。
var consumer = new MyConsumer(
LogManager.GetLogger("My"));
在创建MyConsumer的实例时,负责创建的代码知道这个特定的consumer对象使用哪个实现ILog接口的类,因此可以根据上下文提供正确的实现。
DI和服务定位器是实现松散耦合的两种互斥方案。技术上,两种都是可行的,但DI没有服务定位器的缺点。
DI的唯一缺点是它不像服务定位器那样易于理解。想要成功实现DI,你需要克服一些障碍。
学习DI的其中一个挑战,也是你首先碰到的最难的问题:如何获取一个接口的实例?好消息是一旦你理解构造函数注入只是简单地通过构造函数请求一个实例,你就跨越了这个最艰难的障碍。
接下来的挑战比较容易解决,往后一个更加容易。我喜欢把这些挑战想象成你需要攀越的山。第一个又高又陡,但下一个会比较容易,从那之后很快就会变得平坦:

在成功实现DI的路上,你的第一个障碍是理解通过构造函数注入把构建consumer对象及其依赖的责任委托给第三方。这个第三方就是对象组合的根(Composition Root),它是应用程序里的一个独立的点,整个对象图都是在这里构建的。因为对象组合的根负责构建整个对象图,所以它掌握了整个上下文,这使它可以对谁依赖谁这个问题做出明智的决定。
这可能吓跑了一些开发者,因为他们害怕这会导致性能问题,但事实并非如此。
对于大多数人来说,第二个障碍可能是某个依赖的确定需要一个运行时的值。这种情况通常发生在某个依赖要等用户在用户界面上做出特定的选择时才能确定。对于这种情况,抽象工厂通常是一个解决方案。
根据我的经验,最先的两个障碍是最难克服的。其它挑战也会出现,但一般都是个别现象。在我的书的第六章里,我收集了人们可能碰到的常见问题,以及解决它们的办法。
不管怎样,一旦你对DI形成了正确的心智模型,任何挑战都能轻易解决的。
Mark Seemann 是AutoFixture的创作者,也是《Dependency Injection in .NET》的作者。他是一个专业的软件开发者和架构师,他住在丹麦的哥本哈根,目前是一家丹麦咨询公司Commentor的软件架构师。他喜欢阅读、画画、弹吉他、好酒以及美食。
查看英文原文:Succeeding with Dependency Injection
在多线程并发编程中Synchronized一直是元老级角色,很多人都会称呼它为重量级锁,但是随着Java SE1.6对Synchronized进行了各种优化之后,有些情况下它并不那么重了,本文详细介绍了Java SE1.6中对于锁的性能优化,以及锁的存储结构及升级过程。
本次分享将首先介绍现代富文本编辑器的组成和实现,然后结合UEditor的开发过程,与参会者分享UEditor在设计和实现的过程中,所涉及到的核心功能的细节实现。
本次演讲视频录制于百度技术沙龙。
我们所开发的应用程序大多都需要提供一个图形用户界面(GUI)。关于GUI应用的架构设计,已经有了Form & Control、MVC,、MVP、 Passive View等多种模式。模式可以帮助我们建立优雅的架构,但前提是弄清楚模式的应用场景。弄清楚GUI应用面临的设计上的问题,有助于我们正确的挑选设计方案。
MongoDB是一种非常易用的NoSQL方案,Brian C. Dilley在这篇文章里介绍了MongoDB的优劣势,并介绍了MJORM项目。MJORM用于MongoDB,是一个没有注解的Java ORM库。
随着网络基础设施的逐步成熟,从RPC进化到Web Service,并在业界开始普遍推行SOA,再到后来的RESTful平台以及云计算中的PaaS与SaaS概念的推广,分布式架构在企业应用中开始呈现出不同的风貌,然而殊途同归,这些分布式架构的目标仍然是希望回到建造巴别塔的时代,系统之间的交流不再为不同语言与平台的隔阂而产生障碍。
精益软件开发方法因其对市场和交付的重视和在各种场景下体现出的适应能力正在获得广泛的关注。特别是在精益创业(Lean Startup)渐渐兴起和技术日新月异的今天,其"极端"的思想也变得越来越必要和可行。 InfoQ就此主题对他做了深入的采访。
4 条回复
关注此讨论 回复