包建强的开源地带
我的微软梦,实现了一半
博客园
社区
首页
新随笔
联系
管理
订阅
随笔- 327 文章- 3 评论- 1139
被遗忘的设计模式——1.不变模式(Immutable)
本系列目录
代码示例下载
不
变模式
,这是一个非常基础的模式。
从对象的健壮性来思考:
这些对象共享相同对象的引用,为此,在对象构造好之后,不允许改变共享对象的内容。这就是不变模式,在程序中使用它的地方越合适,程序将越健壮,可维护性就越强。
从并发的角度来思考:
不变模式解决的是如何处理共享对象的问题。当多个对象使用或修改同一个类实例——也就是共享对象的时候,往往会有同步问题;而在多线程异步调用的情况下,则更难以控制这个共享对象的状态。
一种解决办法是,使用了Lock的机制来锁住对象,强制进行同步,但是会增加额外的开销。所以,能避免尽量避免使用Lock。故而,有另一种解决方案:即新建一个有着不同内容的对象,来替换原对象,其中,旧对象中未改变的值会复制到新对象中,而改变的值会使用新值——这种实现方式就称为不变模式。
Flyweight模式一般使用
不变模式
来实现享元,参见我的《我也设计模式》的Flyweight一章。
关键是这个基础类的设计,让我们考察一下复数类
Plural
的加法:
注意到,x和y字段都是私有且只读的,不对外暴露,它们相应的属性也是只读的:
private
readonly
double
x;
private
readonly
double
y;
public
double
X
{
get
{
return
x; }
}
public
double
Y
{
get
{
return
y; }
}
我们只能在构造函数中初始化这两个字段,以后不能再进行修改——这也是“不变”一词的由来:
public
Plural(
double
x,
double
y)
{
this
.x
=
x;
this
.y
=
y;
}
需要指出的是,对于我们这个复数类的加减乘除运算,一般使用运算符重载的技术,其实,也可以使用不变模式来实现,逻辑是:每个复数实例都是不可改变的,在加减乘除运算方法中,创建新的实例,并在其构造函数中设定新的参数,如下面的Add方法:
public
Plural Add(Plural P)
{
return
new
Plural(
this
.x
+
P.x,
this
.y
+
P.y);
}
对于基础类Plural,确实没有暴露他自身的属性,但是,他的子类却有可能将其暴露出来,所以,一般要把这个基础类设为不可派生的:
public
sealed
class
Plural
不变模式在.NET中最广泛的使用就是String类的实现。我们知道,字符串是不可改变的。对于以下操作:
String s
=
"
Jax
"
;
s
+=
"
Bao
"
;
s
=
s.Substring(
3
);
无论是ToUpper还是Substring等函数,都是新建了一个字符串,并重新将该字符串的引用添加到原来的变量s上。另外运算符重载+=,也是这么实现的。
几点注意:
1.构造函数是不需要同步控制的。对CLR认识深刻的人,会认为这是一句废话。毕竟,new还没做好呢,又怎么能Lock一个对象,hoho。
2.仔细观察上面的Add方法:
P.x为什么可以使用呢?x不是P对象的一个私有成员么?至少一开始我是这么认为的,但是编译期和runtime却运行良好。
OK,在Position类外部,确实是访问不了Position对象的x私有字段,为此需要公开其只读属性;但是,就在Position类内部,p作为Add方法的一个参数,却可以访问它自身的这个私有对象。重温private的定义:完全私有的,只有当前类中的成员能访问到。以上是我暂时能想到的一些思路,希望大家能给我更合理的解释。
下一篇:过滤器模式(Filter)
posted @ 2008-06-30 14:07
包建强
阅读(2208)
评论(16)
编辑
收藏
所属分类:
Design Patterns
发表评论
回复
引用
查看
#1楼
2008-06-30 14:52 |
杨同学
immutable 不算是一种设计模式吧,博主
回复
引用
查看
#2楼
[
楼主
]2008-06-30 14:59 |
包建强
@杨同学
何以见得?难道不在GOF中的,都不算么?
回复
引用
查看
#3楼
2008-06-30 15:05 |
taowen
再深入谈一下什么时候适用immutable吧.
回复
引用
查看
#4楼
2008-06-30 15:41 |
U2U
这个模式太耗资源了吧
回复
引用
查看
#5楼
2008-06-30 15:43 |
Allen Lee
说到“不变性”(immutability),就不能不提函数式编程了,在诸如F#的函数式编程语言里,对象默认就是“不可变的”(immutable)。在F#里,上面的Plural类可以这样写:
type Plural =
{ X: double; Y: double }
member this.Add p = { X = this.X + p.X; Y = this.Y + p.Y }
Plural的对象实例一旦创建完毕就不能修改了:
let p1 = { X = 2.1; Y = 3.2 }
回复
引用
#6楼
2008-06-30 15:48 |
未登录的包包 [未注册用户]
小A,
你帮我仔细分析一下我在文章下面提出的问题吧——注意2。我至今还找不到一个合理的解释。多谢多谢!
回复
引用
查看
#7楼
2008-06-30 16:16 |
Allen Lee
@未登录的包包
这个问题曾经在
http://space.cnblogs.com/group/topic/1919/
提出过,脑袋在那里的4楼给出了解释。
回复
引用
#8楼
2008-06-30 16:33 |
未登录的包包 [未注册用户]
@小A
多谢,已经看到。
类的私有成员只能从位于该类内部的【词法环境】中访问。至于是否真正是类内部发生的访问是无法限制的。因此,一个对象的私有成员是可以被别的对象访问的,只要位于该类内部的词法环境中。
回复
引用
查看
#9楼
2008-06-30 16:56 |
Gray Zhang
我记得private是“只能由本类的对象访问”而不是“只能有对象自身访问”,因此在类中访问同类型的另一对象的private字段是可以的
回复
引用
查看
#10楼
2008-06-30 16:57 |
杨同学
严格的说Immutable 应该不算是设计模式。
参照维基百科:
http://en.wikipedia.org/wiki/Design_pattern_
(computer_science)
1. 把类设计成不变的还有一个好处就是有利于提高性能上。特别对于体积比较小并且被重复创建多个实例的类。
2. 如果一个物体是不可修改的, 那么就无需监听 PropertyChanged 事件。 在数据绑定方面有利于精简代码清晰逻辑。
假设Survey类中有这么一个DepthUnit 属性:
class Survey : INotifiedPropertyChanged
{
public Unit DepthUnit
{
get{ return this.depthUnit;}
set{ this.depthUnit = value;
PropertyChanged(this,new PropertyChangedEventArgs("DepthUnit"));
}
}
如果Unit 类不是 immutable 的, 有两种方式篡改这个属性。
-通过属性赋值:
Unit meter = new Unit("m");
Survey.DepthUnit =meter;
-通过修改Unit实例: Survey.DepthUnit.Name = "m";
由于第二种方式的存在。想监听 DepthUnit 属性变化这个事件就需要使 Unit 类实现 INotifiedPropertyChanged 接口。 在DepthUnit 中注册并监听 Unit类的 Name 属性事件,再而触发 Survey 类中的 DepthUnit 属性改变事件。 在每一个有Unit类作为属性的类里面都要使用同样的方法, 代码变得冗长并且很乱。
目前最简单的方法就是吧Unit的 Name属性改成只读的。 这样第二种篡改的方式将不再存在,一切简单了很多。
不清楚这个算不算是immutable 类的一个好处... , 或者对这个问题有想法的请赐教.....
回复
引用
查看
#11楼
2008-06-30 23:46 |
笑笑江南
这个是设计模式?
回复
引用
查看
#12楼
2008-07-01 00:09 |
Angel Lucifer
/* 故而,有另一种解决方案:即新建一个有着不同内容的对象,来替换原对象,其中,旧对象中未改变的值会复制到新对象中,而改变的值会使用新值——这种实现方式就称为不变模式。*/
Immutable 的对象对于并发来说因为不需要同步,从这点上看的确有性能上的提升。
但是也应当注意到,这种场景有限。
同时,在高负载,高并发的情况下,如4楼 U2U 老兄所说,非常耗费资源。这种情况下,垃圾对象频繁创建,导致 GC 频繁进行回收。.NET 新建一个 Heap 对象速度非常快(但稍慢于在栈上分配对象),但是回收起来却很麻烦。还不如 Copy on Write好用。
回复
引用
查看
#13楼
2008-07-01 00:36 |
曲滨*銘龘鶽
@杨同学
设计模式的定义是什么?你知道吗?
估计圆子里能说清楚的不多、呵呵?
回复
引用
查看
#14楼
2008-07-01 01:01 |
杨同学
@曲滨*銘龘鶽
定义在维基百科里面有, 我给了连接的,你去看看吧。
回复
引用
查看
#15楼
2008-07-01 06:20 |
怪怪
稍微有点偏重于实现模式, 而不是设计, 不过这种思路还是有很多用武之地的~
回复
引用
查看
#16楼
2008-07-01 14:38 |
装配脑袋
VB的匿名类,凡是标注Key的属性都是不变属性;而C#的匿名类则必须就是不变类型。比如
Dim a = New {Key .Name = "Harry", Key .Age = 12 } '不变的说
Dim b = New {.Name = "Potter", .Age = 14 } '可变的说
新用户注册
刷新评论列表
标题
姓名
主页
Email
(博主才能看到)
验证码
*
看不清,换一张
[
登录
][
注册
]
内容(请不要发表任何与政治相关的内容)
网站首页
新闻频道
社区
小组
博问
网摘
闪存
找找看
Remember Me?
登录
使用高级评论
新用户注册
返回页首
恢复上次提交
[使用Ctrl+Enter键可以直接提交]
该文被作者在 2008-06-30 14:17 编辑过
"五向定位"职业成长路线公开课(上海、南京、大连)
Google站内搜索
相关文章:
小菜编程成长记(十三 设计模式不能戏说!设计模式怎就不能戏说?)
程序人生演讲内容摘要 ---侯捷
.NET设计模式系列文章
.NET设计模式(2):单件模式(Singleton Pattern)
VS2008里的网页,中文一编辑就变成了数字
Sql Server 2005 CLR 调用COM组件出错
XUnit Test Patterns这本书值得看看
UML和模式应用
相关链接:
所属分类的其他文章:
被遗忘的设计模式——1.不变模式(Immutable)
一些被遗忘的设计模式
我也设计模式——22.Iterator
我也设计模式——19.Mediator
我也设计模式——15.Chain of Responsablity
我也设计模式——9.Bridge
我也设计模式——16.Interpreter
我也设计模式——24.Template Method
我也设计模式——23.Strategy
我也设计模式——17.State
最新IT新闻:
微型博客Twitter取消IM服务 称其ROI差
用手机聊Gtalk的方法以及应用总结
Google开拓美政府机构市场 微软业务受冲击
消息称苹果正在开发iTunes网络电视
微软周一开电话会议 预计将发布Silverlight2.0
公告
姓名:包建强
位置:中国 上海
学历:复旦大学数学系 本科
工作:某外企医疗研发中心 软件工程师
MSN:bjq_ren@hotmail.com
MVP:2008.7——2009.7
MVP配置
常用链接
我的随笔
我的空间
我的短信
我的评论
更多链接
我的文章
我的参与
最新评论
我的标签
我管理的小组
博客园精华集出版小组
读书(Books)
写书译书小组
随笔分类
.NET C#(6)
(rss)
.NET CLR(25)
(rss)
.NET MSIL(39)
(rss)
.NET Reflection(6)
(rss)
.NET Serializable(6)
(rss)
.NET好书逐个评(3)
(rss)
AJAX(3)
(rss)
ASP.NET 2.0(14)
(rss)
Data Structures(2)
(rss)
Design Patterns(29)
(rss)
Open SourceCode(4)
(rss)
Others(54)
(rss)
SharpDevelop 0.92(11)
(rss)
SQLServer研究(3)
(rss)
WCF(2)
(rss)
WF(5)
(rss)
WPF(106)
(rss)
包包版网络棋牌大厅(10)
(rss)
包包点评
(rss)
博客园精花集(21)
(rss)
随笔档案
2008年10月 (4)
2008年9月 (17)
2008年8月 (14)
2008年7月 (28)
2008年6月 (11)
2008年5月 (15)
2008年4月 (58)
2008年3月 (26)
2008年2月 (8)
2008年1月 (1)
2007年10月 (31)
2007年9月 (30)
2007年8月 (9)
2007年7月 (7)
2007年5月 (3)
2007年4月 (36)
2007年3月 (20)
2006年11月 (4)
最新随笔
1. 我读过的世界名著
2. 包包技术书籍推荐
3. 十一节打博得之门2
4. 微软10月份mvp名单发布,祝贺博客园中当选的兄弟们!
5. 《博客园精华集---软件工程分册》第三轮筛选结果
6. 《博客园精华集》五项联合声明
7. 推荐一本SQL经典书籍
8. 很多头绪,有点乱,理清一下
9. 发布塔罗牌21张
10. (翻译)《Expert .NET 2.0 IL Assembler》 第八章 基本类型和签名(二)
积分与排名
积分 - 184332
排名 - 192
最新评论
1. re: 《博客园精华集---软件工程分册》第三轮筛选结果
呵呵,啊……,看到自己的文章了,呵呵!
无论如何谢谢DongDong的点评,吸收了,万分感谢! (刚刚)
2. re: 我读过的世界名著
多看看诸子百家的东西吧 (戏水 ~)
3. re: 我读过的世界名著
我觉得您多看看中国老祖宗留下的东西 远比看所谓的世界名著强得多。 (戏水 ~)
4. 请教wpf文本框如何按回车换行
请教wpf文本框如何按回车换行 (zhangyu111)
5. re: 我读过的世界名著
莎士比亚全集——没看过四大悲剧就不要说爱好文学!
===============================
这。。。 (江南白衣)
6. re: 我读过的世界名著
博主有时间在各列列中国文学中值得一看的吧,呵呵,本人基本上只看国内的,特别喜欢茅盾文学奖系列 (会长)
7. re: 《博客园精华集》五项联合声明
期待nET3.5 (网碾平)
8. re: 包包技术书籍推荐
哎,好像就有3本 AJAX2本和wcf编程 (李永京)
9. re: 《博客园精华集》五项联合声明
希望早日看到书籍成功出版 (生鱼片)
10. re: 《Programming WPF》翻译 第9章 自定义控件
老兄,你要是有时间,将这本书做个翻译版啊。 (从天而降)