您的位置:首页 > 其它

关于《设计模式》与《设计模式沉思录》中提到的“常露齿嘻笑的猫”(Cheshire Cat)的说明

2011-10-01 15:50 309 查看
最近在看GoF的《设计模式》,在此之前看了John Vlissides的《设计模式沉思录》,在“沉思录”P42页脚注中,作者提到

“在C++中这样的定义是难以通过任何强制性的方法实现的[Schmidt96a]。例如,只要用一条简单的#define语句来把private定义为public,我们就可以让所有私有成员变成共有成员。避免这种篡改的一种方法是根本不在头文件中定义成员变量。相反,我们把成员变量和其他机密的实现细节定义在另一个单独的、不公开的头文件中。一个与此紧密相关的模式是BRIDGE……”


,作者可谓点到即止。

而在《设计模式》P102页的下边部分

“Carolan[Car89]用‘常露齿嘻笑的猫’(Cheshire Cat)描述这一分离机制。在C++中,Implementor类的类接口可以在一个私有的头文件中定义,这个文件不提供给客户。这样你就对客户彻底隐藏了一个类的实现部分。”


什么是‘常露齿嘻笑的猫’(Cheshire Cat)?(转自:http://baike.soso.com/h7921075.htm?sp=l7921076

柴郡猫(Cheshire cat)是英国作家刘易斯·卡罗尔(Lewis Carroll,1832-1898)创作的童话《爱丽丝漫游奇境记(Alice's Adventure in Wonderland)》中的虚构角色,形象是一只咧着嘴笑的猫,拥有能凭空出现或消失的能力,甚至在它消失以后,它的笑容还挂在半空中。卡罗尔创作这个角色的灵感可能来源于英国俗语“笑得像一只柴郡猫”(grin like a Cheshire cat),该俗语的来源众说纷纭,有的说是柴郡盛产一种做成笑脸猫形状的奶酪,有的说是当地有一位贵族,他的大衣袖子上画了一只狮子,狮子画得很糟糕,倒像一只笑脸猫,还有人说是来自柴郡一位叫Caterling的笑容丑陋的护林员的绰号。
  《爱丽丝漫游奇境记》里的柴郡猫出现于第六章,出场时坐在公爵夫人家的壁炉前,爱丽丝看到它一直在咧着嘴笑,便问公爵夫人为什么它在笑,公爵夫人告诉她因为那是一只柴郡猫。
  "Please would you tell me,"said Alice,a little timidy,for she was not quite sure whether it was good manners for her to speak first,"why your cat grins like that?"
  "It's a Cheshire cat,'said the Duchess,"and that's why." 
  离开公爵夫人家后,柴郡猫指给了爱丽丝去三月兔和帽匠家的路,后来在女王的槌球赛场上又在爱丽丝面前出现,连动辄叫喊砍头的女王也对它无计可施。
  或许由于其神秘感,这只总是咧嘴微笑着、不参与任何事而保持冷眼旁观的柴郡猫一直是《爱丽丝漫游奇境记》中最受欢迎的角色之一。后人在戏仿《爱丽丝漫游奇境记》的作品中经常有这只猫的身影,例如漫画《红茶王子》的一部番外篇和《樱兰高中HOST部》的一集;吉卜力的动画电影《龙猫》中咧着嘴笑的猫巴士,《潘多拉之心》中的笑面猫也受了柴郡猫的形象影响。


那Cheshire Cat到底讲的是什么回事呢?去http://www.acm.org/sigs查,未果。按照GoF的参考文献上说,Cheshire Cat来自于John Carolan在1989年的文章“Constructing bullet-proof classes”,索性去Google搜这篇文章吧~

没找到原文,但找到了篇引用原文的文章:http://wiki.hsr.ch/Prog3/files/overload72-FINAL_DesigningHeaderFiles.pdf

Cheshire Cat
● A private “representation” class is written that embodies the
same functionality and interface as the naïve class – however,
unlike the naïve version, this is defined and implemented
entirely within the implementation file. The public interface of
the class published in the header is unchanged, but the private
implementation details are reduced to a single member variable
that points to an instance of the “representation” class – each
of its member functions forwards to the corresponding function
of the “representation” class.
● The term “Cheshire Cat” is an old one, coined by John Carollan
over a decade ago [2]. Sadly it seems to have disappeared from
use in contemporary C++ literature. It appears described as a
special case of the “Bridge” pattern in Design Patterns [3], but
the name “Cheshire Cat” is not mentioned. Herb Sutter [4]
discusses it under the name “Pimpl idiom”, but considers it only
from the perspective of its use in reducing physical
dependencies. It has also been called “Compilation Firewall”.
● Cheshire Cat requires “boilerplate” code in the form of
forwarding functions that are tedious to write and (if the
compiler fails to optimise them away) can introduce a slight
performance hit. It also requires care with the copy semantics
(although it is possible to factor this out into a smart pointer
[5]). As the relationship between the public and implementation
classes is not explicit it can cause maintenance issues.


译文如下:

柴郡猫

1、一个私有“展示”类被写成与朴实类包含相同函数和接口,但是不朴实版本的类不同的是,它(私有“展示”类)整个被在一个实现文件中定义和实现。在头文件中发布的类的公共接口不变,然而私有实现的细节被缩减成一个单个成员变量,该变量指向一个“展现”类的实例,它(在头文件中发布的类)的所有成员函数(调用)都被转送(“委托”更恰当些~)给“展示”类的相应函数。

2、“柴郡猫”(Cheshire Cat)是一个旧的说法,由John Carollan 在10年前创造的。不幸的是这种说法貌似在现代C++文献中已经不再使用了。它被描述成《设计模式》中“Bridge”模式的一种特殊形式,但是“柴郡猫”(Cheshire Cat)没有被提及。Herb Sutter以“Pimpl idiom”名字讨论过它,但是只是从它在减少物理依赖的作用方面关注了它。它同时被叫做“编译防火墙”。

3、“柴郡猫”(Cheshire Cat)需要转送函数形式的“照本宣科”的代码(“硬编码”),这些代码通常冗长且(如果编译器没有将它们优化掉的话)会带来性能上的下降。它也需要关注复制语义(尽管可以将这点提取到智能指针中)。由于公共和实现类之间的关系不是显式的,所以它(Cheshire Cat)可能引起维护上的问题。
Cheshire Cat的示例代码如下:
// cheshire_cat.hpp Cheshire Cat -
// implementation hiding example
#ifndef INCLUDED_CHESHIRE_CAT_HPP_ARG_20060303
#define INCLUDED_CHESHIRE_CAT_HPP_ARG_20060303
#include <string>
#include <utility>
namespace cheshire_cat
{
class telephone_list
{
public:
telephone_list(const std::string& name);
~telephone_list();
std::string get_name() const;
std::pair<bool, std::string>
get_number(const std::string& person)
const;
telephone_list&
add_entry(const std::string& name, 
const std::string& number);
private:
class telephone_list_implementation;
telephone_list_implementation* rep;
telephone_list(const telephone_list& rhs);
telephone_list& operator=
(const telephone_list& rhs);
};
}
#endif


朴实示例代码如下:

// naive.hpp - implementation hiding
// example.
#ifndef INCLUDED_NAIVE_HPP_ARG_20060303
#define INCLUDED_NAIVE_HPP_ARG_20060303
#include <string>
#include <utility>
#include <map>
#include <algorithm>
#include <ctype.h>
namespace naive 
{
/** Telephone list. Example of implementing a 
*telephone list using a naive implementation.
*/
class telephone_list
{
public:
/** Create a telephone list.
* @param    name    The name of the list.
*/
telephone_list(const std::string& name);
/** Get the list's name.
* @return   the list's name.
*/
std::string get_name() const;
/** Get a person's phone number.
* @param    person  The person's name
* (must be an exact match)
* @return   pair of success flag and (if
* success) number.
*/
std::pair<bool, std::string>
get_number(const std::string& person)
const;
/** Add an entry. If an entry already
* exists for this person it is overwritten.
*
*   @param  name    The person's name
*   @param  number  The person's number
*/
telephone_list&
add_entry(const std::string& name, 
const std::string& number);
private:
typedef std::map<std::string,
std::string> dictionary_t;
std::string  name;
dictionary_t dictionary;
telephone_list(const telephone_list& rhs);
telephone_list& operator=
(const telephone_list& rhs);
};
}
#endif


可以发现,如果用户使用

#define private public


则朴实代码中的所有private权限的变量将全部可见!完全无法隐藏!

而Cheshire Cat代码中,由于没有在文件中定义成员变量(至少没有定义那么多敏感成员变量),所以Cheshire Cat代码不会暴露实现细节,顶多是暴露了

class telephone_list_implementation;
telephone_list_implementation* rep;




而如果class telephone_list_implementation的实现是在一个lib或dll文件中,那么用户根本无法通过

#define private public


方式使class telephone_list_implementation的细节暴露!因为用户没有class telephone_list_implementation的源代码……

用户拿到的最多是telephone_list_implementation* rep,而无法暴露telephone_list_implementation* rep的细节。




                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: