<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
		>
<channel>
	<title>Comments on: 冒号课堂§10.1：多态类型</title>
	<atom:link href="http://blog.zhenghui.org/2009/10/20/colon-class-10_1/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.zhenghui.org/2009/10/20/colon-class-10_1/</link>
	<description>自然、人类、机器</description>
	<lastBuildDate>Sat, 14 Jan 2012 02:01:40 +0000</lastBuildDate>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
	<item>
		<title>By: 郑晖</title>
		<link>http://blog.zhenghui.org/2009/10/20/colon-class-10_1/comment-page-1/#comment-131</link>
		<dc:creator>郑晖</dc:creator>
		<pubDate>Sat, 05 Dec 2009 08:36:43 +0000</pubDate>
		<guid isPermaLink="false">http://blog.zhenghui.org/?p=506#comment-131</guid>
		<description>严格说来这的确违背了LSP。假设IAccount对Transfer的amount没有限制，那么当一个类型为IAccount的对象调用Transfer时，代码中到底该不该判断该对象究竟属于PersonalAccount还是EnterpriseAccount？如果作这样的判断，那么（多态）抽象被破坏，代码可能违背开闭原则（假如今后出现新的IAccount子类型，对amount有新的限制怎么办？）。如果不作判断，又可能抛出异常。唯一的补救办法是：在IAccount的Transfer规范中声明，不同的子类型可能会因amount不符合条件而抛出异常。
在Java中这样的例子也不少，比如接口List含有add、remove等方法，但有些List的子类型并不支持add或remove（如readonly List）。因此，List的规范中明确指出，有些子类型可能抛出UnsupportedOperationException的异常。这样客户会注意在代码中捕捉该类异常，以防万一。这已是最大限度地维护LSP了，虽然并不是那么理想。</description>
		<content:encoded><![CDATA[<p>严格说来这的确违背了LSP。假设IAccount对Transfer的amount没有限制，那么当一个类型为IAccount的对象调用Transfer时，代码中到底该不该判断该对象究竟属于PersonalAccount还是EnterpriseAccount？如果作这样的判断，那么（多态）抽象被破坏，代码可能违背开闭原则（假如今后出现新的IAccount子类型，对amount有新的限制怎么办？）。如果不作判断，又可能抛出异常。唯一的补救办法是：在IAccount的Transfer规范中声明，不同的子类型可能会因amount不符合条件而抛出异常。<br />
在Java中这样的例子也不少，比如接口List含有add、remove等方法，但有些List的子类型并不支持add或remove（如readonly List）。因此，List的规范中明确指出，有些子类型可能抛出UnsupportedOperationException的异常。这样客户会注意在代码中捕捉该类异常，以防万一。这已是最大限度地维护LSP了，虽然并不是那么理想。</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Todd</title>
		<link>http://blog.zhenghui.org/2009/10/20/colon-class-10_1/comment-page-1/#comment-130</link>
		<dc:creator>Todd</dc:creator>
		<pubDate>Sat, 05 Dec 2009 08:08:49 +0000</pubDate>
		<guid isPermaLink="false">http://blog.zhenghui.org/?p=506#comment-130</guid>
		<description>关于这点有个例子想不明白，请指教。比如：IAccount表示抽象的银行账户，定义了Transfer(IAccount target, double amount)转账方法；PersonalAccount和EnterpriseAccount是它的两个派生类；PersonalAccount要求每次转账金额amount &lt; 10000，EnterpriseAccount则无限制。那么是不是说PersonalAccount强化了precondition，LSP原则在这里被打破了？</description>
		<content:encoded><![CDATA[<p>关于这点有个例子想不明白，请指教。比如：IAccount表示抽象的银行账户，定义了Transfer(IAccount target, double amount)转账方法；PersonalAccount和EnterpriseAccount是它的两个派生类；PersonalAccount要求每次转账金额amount &lt; 10000，EnterpriseAccount则无限制。那么是不是说PersonalAccount强化了precondition，LSP原则在这里被打破了？</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: 郑晖</title>
		<link>http://blog.zhenghui.org/2009/10/20/colon-class-10_1/comment-page-1/#comment-114</link>
		<dc:creator>郑晖</dc:creator>
		<pubDate>Tue, 01 Dec 2009 09:56:38 +0000</pubDate>
		<guid isPermaLink="false">http://blog.zhenghui.org/?p=506#comment-114</guid>
		<description>你说得没错，一个是&lt;b&gt;主动的&lt;/b&gt;依赖自造，一个是&lt;b&gt;被动的&lt;/b&gt;依赖注入。前者拥有更多的自主权，但也承担更多的职责——负责依赖的建造和销毁。Spring、Guice等具有依赖注射机制的框架提倡用后者，由框架来统一管理依赖，不仅减少了应用程序的代码量，更使得依赖体系更加灵活和可定制（通常依赖的是抽象类型而非具体类型，并且可以在metadata中定义），大大减少了系统组件之间的耦合。</description>
		<content:encoded><![CDATA[<p>你说得没错，一个是<b>主动的</b>依赖自造，一个是<b>被动的</b>依赖注入。前者拥有更多的自主权，但也承担更多的职责——负责依赖的建造和销毁。Spring、Guice等具有依赖注射机制的框架提倡用后者，由框架来统一管理依赖，不仅减少了应用程序的代码量，更使得依赖体系更加灵活和可定制（通常依赖的是抽象类型而非具体类型，并且可以在metadata中定义），大大减少了系统组件之间的耦合。</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Todd</title>
		<link>http://blog.zhenghui.org/2009/10/20/colon-class-10_1/comment-page-1/#comment-113</link>
		<dc:creator>Todd</dc:creator>
		<pubDate>Tue, 01 Dec 2009 09:15:51 +0000</pubDate>
		<guid isPermaLink="false">http://blog.zhenghui.org/?p=506#comment-113</guid>
		<description>文中Authenticator和Keeper/Encrypter的组合关系的建立有两种典型的方式：1. 在Authenticator内部自行创建Keeper/Encypter；2.在Authenticator外部创建Keeper/Encypter，并通过构造函数或Setter传入。起初我没有想明白二者的区别，以至于在使用的时候有困惑。现在我的看法是：如果Authenticator应该负责Keeper/Encypter的生命周期，那就应该放内部；否则就应该从外部传入。比如：人和心脏属于前者，而汽车和轮胎则属于后者。人与心脏的生命周期是绑定的；而汽车报废了或许轮胎还可以继续换到其他地方用。不知这样理解是否正确？</description>
		<content:encoded><![CDATA[<p>文中Authenticator和Keeper/Encrypter的组合关系的建立有两种典型的方式：1. 在Authenticator内部自行创建Keeper/Encypter；2.在Authenticator外部创建Keeper/Encypter，并通过构造函数或Setter传入。起初我没有想明白二者的区别，以至于在使用的时候有困惑。现在我的看法是：如果Authenticator应该负责Keeper/Encypter的生命周期，那就应该放内部；否则就应该从外部传入。比如：人和心脏属于前者，而汽车和轮胎则属于后者。人与心脏的生命周期是绑定的；而汽车报废了或许轮胎还可以继续换到其他地方用。不知这样理解是否正确？</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: 郑晖</title>
		<link>http://blog.zhenghui.org/2009/10/20/colon-class-10_1/comment-page-1/#comment-85</link>
		<dc:creator>郑晖</dc:creator>
		<pubDate>Sat, 07 Nov 2009 03:08:10 +0000</pubDate>
		<guid isPermaLink="false">http://blog.zhenghui.org/?p=506#comment-85</guid>
		<description>1)文中有一句话：“没有继续采用Java，是因为它的泛型仍离不开子类型多态”。Java虽然支持GP，但在template中的参数不能是简单的Object（C++中template的参数却可以不标明类型），必须涉及到子类型多态（如&lt;T extends KeyValueKeeper&gt;），否则无法在实现代码中调用泛型参数的方法。这样一来，两类多态（子类型多态与参数多态）混在一起，不利于说明问题（本篇的目的是&lt;strong&gt;分别&lt;/strong&gt;介绍三类多态）。
2)如果Authenticator类为其KeyValueKeeper或Encrypter成员开放setter方法，即可让客户在运行期修改策略。</description>
		<content:encoded><![CDATA[<p>1)文中有一句话：“没有继续采用Java，是因为它的泛型仍离不开子类型多态”。Java虽然支持GP，但在template中的参数不能是简单的Object（C++中template的参数却可以不标明类型），必须涉及到子类型多态（如&lt;T extends KeyValueKeeper>），否则无法在实现代码中调用泛型参数的方法。这样一来，两类多态（子类型多态与参数多态）混在一起，不利于说明问题（本篇的目的是<strong>分别</strong>介绍三类多态）。<br />
2)如果Authenticator类为其KeyValueKeeper或Encrypter成员开放setter方法，即可让客户在运行期修改策略。</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Pat</title>
		<link>http://blog.zhenghui.org/2009/10/20/colon-class-10_1/comment-page-1/#comment-82</link>
		<dc:creator>Pat</dc:creator>
		<pubDate>Sat, 07 Nov 2009 00:33:44 +0000</pubDate>
		<guid isPermaLink="false">http://blog.zhenghui.org/?p=506#comment-82</guid>
		<description>好文章，很受益！对于文中一处所述不太理解：以上代码与Java版的策略模式代码很相似，主要的区别是把KeyValueKeeper和Encrypter两个接口换成了模板参数。由于模板是在编译期间实例化的，因此没有动态绑定的运行开销，但缺点是不能动态改变策略[5]。
5. 对用Java实现的Authenticator类（策略模式版）稍作修改，就能让客户动态改变策略。 

我的疑惑是，
1）这文章中的C++代码跟JAVA代码的可比性不太清楚，可能是我的C++太差。您提到的GP范式，JAVA不支持么？
2）但我也想明白您说的“对用Java实现的Authenticator类（策略模式版）稍作修改，就能让客户动态改变策略”该如何实现？ 谢谢</description>
		<content:encoded><![CDATA[<p>好文章，很受益！对于文中一处所述不太理解：以上代码与Java版的策略模式代码很相似，主要的区别是把KeyValueKeeper和Encrypter两个接口换成了模板参数。由于模板是在编译期间实例化的，因此没有动态绑定的运行开销，但缺点是不能动态改变策略[5]。<br />
5. 对用Java实现的Authenticator类（策略模式版）稍作修改，就能让客户动态改变策略。 </p>
<p>我的疑惑是，<br />
1）这文章中的C++代码跟JAVA代码的可比性不太清楚，可能是我的C++太差。您提到的GP范式，JAVA不支持么？<br />
2）但我也想明白您说的“对用Java实现的Authenticator类（策略模式版）稍作修改，就能让客户动态改变策略”该如何实现？ 谢谢</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: 郑晖</title>
		<link>http://blog.zhenghui.org/2009/10/20/colon-class-10_1/comment-page-1/#comment-58</link>
		<dc:creator>郑晖</dc:creator>
		<pubDate>Tue, 20 Oct 2009 16:06:38 +0000</pubDate>
		<guid isPermaLink="false">http://blog.zhenghui.org/?p=506#comment-58</guid>
		<description>DbC除了能保证基类的class invariant在派生类中仍然有效外，还能保证基类的precondition在派生类中不被强化，postcondition不被弱化。</description>
		<content:encoded><![CDATA[<p>DbC除了能保证基类的class invariant在派生类中仍然有效外，还能保证基类的precondition在派生类中不被强化，postcondition不被弱化。</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Todd</title>
		<link>http://blog.zhenghui.org/2009/10/20/colon-class-10_1/comment-page-1/#comment-57</link>
		<dc:creator>Todd</dc:creator>
		<pubDate>Tue, 20 Oct 2009 15:48:53 +0000</pubDate>
		<guid isPermaLink="false">http://blog.zhenghui.org/?p=506#comment-57</guid>
		<description>文中提到“一个是在语义上遵循里氏代换原则，另一个是在语法上支持多态（polymorphism）机制”，结合我最近了解的Design by Contract，想到：在C++，Java，C#等语言中，继承/接口只有显式的语法约束，没有显式的语义约束。比如文中第一版Authenticator的store和retrieve，只能由实现者保证其语义正确性。

支持Design by Contract的语言能从一定程度上帮助保证语义正确性，其方法是在基类中定义class invariant，派生类在继承语法的同时也继承了语义（可能不完整）。和传统OO语言相比，它的进步在于提供了更显式地保证语义正确性的手段。

除了Design by Contract外，Unit Test也是保证语义正确性的手段。适用于Authenticator的Unit Test Case都应该适用于其派生类。</description>
		<content:encoded><![CDATA[<p>文中提到“一个是在语义上遵循里氏代换原则，另一个是在语法上支持多态（polymorphism）机制”，结合我最近了解的Design by Contract，想到：在C++，Java，C#等语言中，继承/接口只有显式的语法约束，没有显式的语义约束。比如文中第一版Authenticator的store和retrieve，只能由实现者保证其语义正确性。</p>
<p>支持Design by Contract的语言能从一定程度上帮助保证语义正确性，其方法是在基类中定义class invariant，派生类在继承语法的同时也继承了语义（可能不完整）。和传统OO语言相比，它的进步在于提供了更显式地保证语义正确性的手段。</p>
<p>除了Design by Contract外，Unit Test也是保证语义正确性的手段。适用于Authenticator的Unit Test Case都应该适用于其派生类。</p>
]]></content:encoded>
	</item>
</channel>
</rss>

