﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-dongpo-文章分类-设计模式</title><link>http://www.cppblog.com/dongpo/category/13032.html</link><description>不积跬步，无以至千里；不积小流，无以成江海。</description><language>zh-cn</language><lastBuildDate>Fri, 07 May 2010 15:43:55 GMT</lastBuildDate><pubDate>Fri, 07 May 2010 15:43:55 GMT</pubDate><ttl>60</ttl><item><title>Proxy（代理）模式</title><link>http://www.cppblog.com/dongpo/articles/109764.html</link><dc:creator>学不可以已</dc:creator><author>学不可以已</author><pubDate>Mon, 15 Mar 2010 13:15:00 GMT</pubDate><guid>http://www.cppblog.com/dongpo/articles/109764.html</guid><wfw:comment>http://www.cppblog.com/dongpo/comments/109764.html</wfw:comment><comments>http://www.cppblog.com/dongpo/articles/109764.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/dongpo/comments/commentRss/109764.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/dongpo/services/trackbacks/109764.html</trackback:ping><description><![CDATA[<p><strong>需求：</strong><br>有一个受保护的文件：<br>（1）对文件内容进行加密；<br>（2）任何用户都可以读，但只有管理员用户可以写。</p>
<p><strong>方案1：</strong><br><br><img border=0 src="http://www.cppblog.com/images/cppblog_com/dongpo/proxy1.jpg" width=287 height=176><br><br>FileManager在写文件时，判断要写的文件是否受保护，如果受保护，判断用户是否是管理员。<br>void <br>FileManager::Write(File* file, string s)<br>{<br>&nbsp;if (PROTECTEDFILE == file.GetType() &amp;&amp;<br>&nbsp;&nbsp;ADMINISTRATOR != userId)<br>&nbsp;{<br>&nbsp;&nbsp;return;<br>&nbsp;}<br>&nbsp;file-&gt;Write(s);<br>}</p>
<p><strong>缺点：</strong><br>FileManager的Write函数，需要根据file的具体类型做区分处理。如果ProtectedFile的权限保护规则有变化，需要修改FileManager。FileManager对于权限保护规则的变化，不符合Open-Close原则。</p>
<p><strong>方案2：</strong><br><br><img border=0 src="http://www.cppblog.com/images/cppblog_com/dongpo/proxy2.jpg" width=417 height=193><br><br>文件权限保护规则，放在ProtectedFileProxy中，且它实现了File接口，这样FileManager就可以把ProtectedFileProxy当作普通文件处理。</p>
<p>void<br>ProtectedFileProxy::Write(string s)<br>{<br>&nbsp;if (ADMINISTRATOR == userId)<br>&nbsp;{<br>&nbsp;&nbsp;m_pProtectedFile-&gt;Write(s);<br>&nbsp;}<br>}</p>
<p>void <br>FileManager::Write(File* file, string s)<br>{<br>&nbsp;file-&gt;Write(s);<br>}</p>
<p><strong>总结：</strong><br>1.作用：为其它对象提供一种代理以控制对这个对象的访问。<br>2.效果：Proxy模式在访问对象时引入了一定程度的间接性，这个间接性对用户是透明的，即用户不依赖于这种间接性的变化。附加的间接性有多种用途：<br>（1）Remote Proxy，访问远程对象，就跟访问本地对象一样。如RMI。<br>（2）Virtual Proxy，可以智能的决定创建对象的时机。<br>（3）Protection Proxy，允许在访问一个对象时有一些附加地内务处理（如权限检查）。</p>
<img src ="http://www.cppblog.com/dongpo/aggbug/109764.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/dongpo/" target="_blank">学不可以已</a> 2010-03-15 21:15 <a href="http://www.cppblog.com/dongpo/articles/109764.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Observer模式</title><link>http://www.cppblog.com/dongpo/articles/109763.html</link><dc:creator>学不可以已</dc:creator><author>学不可以已</author><pubDate>Mon, 15 Mar 2010 13:09:00 GMT</pubDate><guid>http://www.cppblog.com/dongpo/articles/109763.html</guid><wfw:comment>http://www.cppblog.com/dongpo/comments/109763.html</wfw:comment><comments>http://www.cppblog.com/dongpo/articles/109763.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/dongpo/comments/commentRss/109763.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/dongpo/services/trackbacks/109763.html</trackback:ping><description><![CDATA[<p><strong>需求：<br></strong>为了及时发布气象信息，气象站检测到温度变化时，立刻通知电视台和广播台。以后可能还会通知移动通信运营商。</p>
<p><strong>方案１：</strong><br>WeatherStation拥有TVStation和RadioStation对象的指针。温度发生变化时，WeatherStation调用TVStation和RadioStation的Update函数，通知他们温度发生了变化。TVStation和RadioStation调用WeatherStation的GetTemperature获取温度数据，并广播出去。</p>
<p><img border=0 src="http://www.cppblog.com/images/cppblog_com/dongpo/observer1.jpg" width=488 height=278><br><strong>缺点：</strong><br>WeatherStation直接依赖于需要被通知的具体类（目前只有TVStation和RadioStation）。被通知的具体类发生变化时，例如需要通知移动通信运营商，WeatherStation需要添加新的成员变量，保存移动通信运营商指针。还需要添加AttachXX和DetachXX接口，修改SetTemperature。也就是说，WeatherStation对于被通知者种类的变化，不符合Open-Close原则。</p>
<p><strong>怎么解决：</strong><br>Open-Close原则的关键在于抽象。WeatherStation不应该依赖于具体的被通知者，而是要依赖于抽象的被通知者。所以，需要把被通知者的跟温度更新有关的接口提取出来，作为抽象基类Observer，具体的被通知者继承Observer。</p>
<p>另外，WeatherStation的注册/取消注册功能，通知观察者功能，可以提取出来作为基类，利于复用。</p>
<p><strong>方案2：<br></strong>Subject类提供了注册/取消注册观察者功能，以及通知观察者功能。WeatherStation继承了Subject类，从而具备了注册/取消注册及通知功能。Observer提供了更新观察者的接口Update。任何想要在WeatherStation变化时收到通知的类，只需要继承Observer，并在实例化时调用Subject的Attach接口注册即可。<br><br><img border=0 src="http://www.cppblog.com/images/cppblog_com/dongpo/observer2.jpg" width=623 height=263><br><br><br>现在，移动通信运营商如果想知道温度变化信息，只需要继承Observer，实例化时调用Subject的Attach接口注册即可。WeatherStation不需要做任何改动。</p>
<p><strong>总结：<br></strong>1.意图<br>&nbsp;定义对象间的一对多的依赖关系，当一个对象的状态发生变化时，所有依赖于它的对象都得到通知并被自动更新。<br>2.适用性<br>&nbsp;一个对象的改变需要通知多个对象，而被通知的对象的种类可能会发生变化。<br>3.优点<br>&nbsp;目标不依赖于具体的观察者，而是依赖于抽象，这就降低了耦合度。当观察者种类发生变化时，目标不需要做任何改变。<br>&nbsp;支持广播通信。目标变化时，不需要指定通知的接收者，而是通知所有注册的观察者。<br>4.缺点<br>&nbsp;因为是广播通信，即使观察者A不关心变化p，在变化p发生时，观察者A仍会收到通知。这会降低效率。<br>&nbsp;如果观察者A关心的数据变化种类特别多，而Update函数又没有参数指定变化类型，观察者A不得不更新所有关心的数据。这也会降低效率。这可以通过给Update函数增加参数，指明更新的数据来解决。<br></p>
<img src ="http://www.cppblog.com/dongpo/aggbug/109763.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/dongpo/" target="_blank">学不可以已</a> 2010-03-15 21:09 <a href="http://www.cppblog.com/dongpo/articles/109763.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Decorator模式</title><link>http://www.cppblog.com/dongpo/articles/109612.html</link><dc:creator>学不可以已</dc:creator><author>学不可以已</author><pubDate>Sat, 13 Mar 2010 07:34:00 GMT</pubDate><guid>http://www.cppblog.com/dongpo/articles/109612.html</guid><wfw:comment>http://www.cppblog.com/dongpo/comments/109612.html</wfw:comment><comments>http://www.cppblog.com/dongpo/articles/109612.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/dongpo/comments/commentRss/109612.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/dongpo/services/trackbacks/109612.html</trackback:ping><description><![CDATA[<p><strong>需求：</strong><br>能从File中读取字符串；<br>能从Buffer中读取字符串；<br>能把读取的字符串反转；<br>能把读取的字符串转为小写。<br><br><strong>方案1：通过继承来解决<br></strong><img border=0 src="http://www.cppblog.com/images/cppblog_com/dongpo/Decorator1.jpg" width=531 height=206><br><br><strong>存在的问题：</strong><br>1.类爆炸。如果再加入一个新的字符串处理，如小写转大写，有多少个数据源，就要增加多少个类；<br>2.如果字符串处理算法变化，或者读取数据的算法变化，需要修改多个类。<br>原因分析：<br>1.读取数据的算法，和字符串处理的算法，应该是相互独立的，可以独立的变化。上述方案把两个方法紧紧地绑定在一起。如果有M个读数据算法，有N个字符串处理算法，则需要M*N个类。这就是类爆炸。<br>2.读取数据的算法没有抽象出来，而是有多个拷贝，分散在各个类中。如果这个算法要改变，就要修改多个类。</p>
<p><strong>方案2：</strong><br><img border=0 src="http://www.cppblog.com/images/cppblog_com/dongpo/Decorator2.jpg" width=274 height=221><br><br><strong>存在的问题：</strong><br>1.所有的特征都放在了抽象层。即使用户不需要readReversedLine、readLowerCaseLine，也需要依赖于它们。<br>2.如果想增加新的字符串处理操作，需要修改抽象层InputStream，从而引起InputStream用户代码的变更。即，InputStream对于字符串处理操作的变更不是开放-关闭的。</p>
<p><strong>方案3：通过组合来解决（Decorator模式）<br></strong>读取数据是InputStream的核心职责，字符串处理是InputStream的附加职责。我们可以通过组合的方法，动态地为读取数据职责添加附加地字符串处理职责。<br><br><img border=0 src="http://www.cppblog.com/images/cppblog_com/dongpo/Decorator3.jpg" width=476 height=292><br><br>string <br>ReverseInputStream::readLine()<br>{<br>&nbsp;string result = m_cStream.readLine();<br>&nbsp;ReverseString(result);<br>&nbsp;return result;<br>}</p>
<p><strong>总结：</strong><br>1.作用：动态地给一个对象添加一些额外地指责。<br>2.优点：<br>&nbsp;可以动态地给对象添加职责，非常灵活，用户需要什么职责，就添加什么职责；<br>&nbsp;附加职责的变化，不会引起用户代码的变化，即开放-关闭。<br>3.缺点：<br>&nbsp;有很多小对象，如ReverseInputStream、LowerCaseInputStream等，增加了系统的复杂性。<br>&nbsp;<br>4.适用性：<br>&nbsp;希望动态地、透明地给单个对象添加职责。添加职责的动作不影响该对象的用户；<br>&nbsp;对象有两种职责（核心职责、附加职责），如果用生成子类的方法进行扩充，会引起类爆炸。</p>
<img src ="http://www.cppblog.com/dongpo/aggbug/109612.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/dongpo/" target="_blank">学不可以已</a> 2010-03-13 15:34 <a href="http://www.cppblog.com/dongpo/articles/109612.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>