[OOD-More C++ Idioms] 律师与委托人 (Attorney-Client)

律师与委托人 (Attorney-Client)

目的

控制访问类实现细节的粒度。

动机

C++中的friend会开始类内部的所有细节,也因此破坏了封装性。C++没有提供可以选择性使用某一部分私有成员的方式,要么全部开放,要么全部拒绝。例如下面例子中的类Foo声明Bar为其友元,可以访问它的所有私有成员。这样增加了耦合性,类Bar也无法单独发布,这样并不太合适。

class Foo
{
private:
  void A(int a);
  void B(float b);
  void C(double c);
  friend class Bar;
};

class Bar {
// 这个类只需要使用Foo::A和Foo::B.
// 但它其实可以访问Foo所有的成员.
};

如果能选择确定需要使用到的一组成员,而不是全部,就可以降低耦合性。而这个律师与委托人的惯用法就可以精准的控制友元所能使用的成员。

解决方案及示例

基本思路是增加一个中间层进行控制。一个客户类可以指定一个律师(Attorney)类作为其友元类,再由此律师类担当其它类使用客户类的代理。与典型的代理(proxy)类不同的是,律师类会限制一个可以使用的成员子集。比如上面的例子中,将Foo改为Client, 再提供一个中间类限制只允许访问Client::A和Client::B。代码如下:

class Client
{
private:
  void A(int a);
  void B(float b);
  void C(double c);
  friend class Attorney;  // 这里指定友元类
};

class Attorney {
private:
  static void callA(Client & c, int a) {
    c.A(a);
  }
  static void callB(Client & c, float b) {
    c.B(b);
  }
  friend class Bar;
};

class Bar {
// 现在Bar通过Attorney类就只能使用Client::A和Client::B了。
};

类图如下:

Attorney类只有私有的inline static函数,每个都持有一个Client实例的引用,再转而调用合适的方法。仅保持私有实现,可以避免被其它类使用。所有需要使用Client都要在Attorney中声明为友元类。如果没有Attorney类,就需要直接修改Client类。

另外还可以使用多个律师(Attorney)类分离出对不同私有实现的访问。

还有一个有趣的案例是提供一个律师(Attorney)类作为多个类的中间人(mediator),来统一提供对它们私有实现的访问。这个设计可以用于解决C++中无法继承友元类所带来的问题,因为私有实现的虚函数是可以被基类调用的。 下面这个例子里,Derived::Func是一个多态实现。通过这个惯用法同样可以使用到Derived中的私有实现。

#include <cstdio>

class Base {
private:
  virtual void Func(int x) = 0;
  friend class Attorney;
public:
  virtual ~Base() {}
};

class Derived : public Base {
private:
  virtual void Func(int x)  {
    printf("Derived::Func\n"); // 虽然没有继承基类中的友元关系,但仍然可以被访问。
  }

public:
  ~Derived() {}
};

class Attorney {
private:
  static void callFunc(Base & b, int x) {
    return b.Func(x);
  }
  friend int main (void);
};

int main(void) {
  Derived d;
  Attorney::callFunc(d, 10);
}

类图如下:

已知的应用

参考

时间: 2024-09-17 04:24:31

[OOD-More C++ Idioms] 律师与委托人 (Attorney-Client)的相关文章

客户被骗1亿失职律师赔800万震动国内律师业

北京市第二中级法院的一声槌响震动了整个律师业:因为受委托的律师失职,导致客户被骗走1亿元资金,3名律师事务所合伙人被法院一审判令赔偿客户800万元损失,并返还100万元律师费.这是国内律师行业迄今为止遭遇的最为高昂的赔偿."打错一起官司,律师赔得倾家荡产"不再是危言耸听,律师业巨大的执业风险引发了极大的关注. 请了律师先行"摸底" 上亿投资还是被骗 2001年7月,河北三河燕化公司准备与北京金晟房地产开发有限公司合作开发紫宸苑住宅小区项目.为查清对方底细,燕化公司聘

AVG黑白通吃大作 《恶魔律师》试玩攻略

逆袭裁判的姊妹?不知各位对经典的PC游戏<逆转裁判>有没有了解,初看到这款美式律政AVG游戏小编就立刻联想到了<逆转裁判>里找寻找种种证据的画面.但是试玩之后才发现这是一款黑白通吃,亦正亦邪的游戏.<逆转裁判>AVG游戏也许很多玩家不了解AVG游戏所指为何,其实AVG就是Adventure Game的简写,统一指代所有冒险游戏,其故事情节往往是以完成某个任务或是解开一个谜题的形式出现的.例如最早期的<生化危机>系列.<古墓丽影>等就 是很经典的A

代理律师:禹有土地证文件现无法断定真假

每经记者 夏子航 发自上海 <每日经济新闻>7月23日.7月28日全国独家发表 <国土局指证:"唐骏校友"禹晋永1500亩土地证造假>和<公司6年零纳税 禹晋永遭高校教师举报诈骗>调查报道之后,禹晋永终于"坐不住"了. 7月31日,禹晋永发出"律师声明",要求本报.<南方都市报>等媒体为其消除影响,否则,将通过诉讼程序解决此事宜.然而,就在本报昨晚截稿时却得到意外的消息:代理禹晋永案的北京市盈科律师

唐骏校友案续代理律师无法断定禹晋永土地证真假

代理律师:禹有土地证文件 现无法断定真假 核心提示:代理禹晋永案的北京市盈科律师事务所"决定退出禹晋永案的代理". <每日经济新闻>7月23日.7月28日全国独家发表<国土局指证:"唐骏校友"禹晋永1500亩土地证造假>和<公司6年零纳税禹晋永遭高校教师举报诈骗>调查报道之后,禹晋永终于"坐不住"了. 7月31日,禹晋永发出"律师声明",要求本报.<南方都市报>等媒体为其消除影响

华润核心矿权被指突击交易律师:将提起行政复议

在距离今日(8月5日)香港高等法院开程序庭对小股东诉华润电力董事会未公布并购金业集团资产案进行聆讯前的四天,8月2日,华润电力的联营公司--太原华润煤业有限公司和山西金业煤焦化集团有限公司签订了<探矿权转让合同>,完成了这桩引起巨大争议的矿权交易.但有山西律师向 <每日经济新闻>记者表示,在8月1日提交的异议申请没有得到答复的情况下,涉嫌强行交易和突击交易,他们将向国土资源部提起行政复议.矿权转让交易距开庭仅4天8月2日,山西省国土资源交易事务中心举行转让鉴证,太原华润煤业有限公司

黄静告反水律师名誉侵权案证据不足败诉

中国法院网讯 4月7日上午九时,黄静诉反水律师崔电博和其前后任职的北京市浩光和包诚律师事务所名誉权纠纷一案在北京宣武区人民院审结,该院以黄静证据不足为由,驳回了黄静的诉讼请求.但该院在判决书中委婉地劝告崔电博,作为专业律师,应在公共场合注意自己的言辞,对自己发表的言论做到客观真实. 据黄静称事情的起因是:2006年3月,她因向华硕电脑公司维权被刑事拘留后,崔电博受其母委托,在侦查阶段代理她涉嫌敲诈勒索一案.后因崔业务水平不精她母亲与之终止了委托代理协议. 2008年12月,她的代理人周成宇与华硕

黄静起诉华硕案代理律师及律所侵犯名誉权

据中国法院网报道,近日,北京市宣武区人民法院受理了黄静诉其华硕案原代理律师崔某.崔某所在的北京市浩光律师事务所,及保管其笔录的北京市包诚律师事务所侵犯其名誉权案. 原告黄静诉称:2006年3月其因向华硕电脑公司维权被刑事拘留后,崔某受原告母亲的委托,在侦查阶段代理原告涉嫌敲诈勒索一案.侦查阶段结束后,因委托人认为崔某业务水平不精终止了委托代理协议.2008年12月3日,原告代理人与华硕电脑公司代理律师参见凤凰卫视中文台<一虎一席谈>节目录制,崔某伙同他人前往节目录制现场,以原告代理人身份在该节

C# Idioms: Enum还是Enum Class(枚举类)

C# Idioms:Enum还是Enum Class(枚举类) marshine (原文排版格式:http://www.marshine.com) reversion:2004/5/28修改说明:感谢Ninputer提到的CLS兼容问题,同时修改了原来版本没有提及的Equals改写,以及修改"=="重载的不完善代码,和增加enum struct内容 reversion:2004/6/4 增加kirc提到的Enum的Flags特性,因为文本超长,新的版本可以在http://www.mar

C# Idioms: Safely方法

C# Idioms: Safely方法 marshine (原文排版格式 http://www.marshine.com) 名称 Safely Method 意图 通过方法保证返回有效(不为空引用,null或Nothing)的对象或抛出异常,当存在多个调用者时简化调用者需要处理null返回值的代码. 动机 一个存放对象的集合或类似功能的容器类,提供了根据键值返回集合成员的接口,如果不存在指定键值的项,则返回一个空引用.例如根据Student的SID(学号)从StudentManager返回Stu