1.4.2 理解使用不可变性的代码

在前面介绍函数式风格的好处时,我们讨论过不可变性(immutability)。我们使用的示例是一个带边框的椭圆,但是代码的具体行为并不清楚。当我们用不可变对象重写了代码以后,它就变得更容易理解。在后面的章节中,我们会回到这个主题并更详细地讨论。此示例的目的是显示在实践中不可变的对象的表现。

再次强调,如果你在此时没能全部掌握,也不要担心。想象一下,我们正在编写一个游戏,其中的角色就是我们的目标,角色可以用类来表示,下面的清单是这个类的一部分:

Listing 1.7 Immutable representation of agame character (C#)

classGameCharacter

{

readonlyint health;           |[1]
把所有字段声明为只读

readonly Point location;       |

public GameCharacter(int
health, Pointlocation)

{

this.health = health;        
|[2] 初始化不可变字段

this.location =location;    
|

}

publicGameCharacter HitByShooting(Point target)

{

int newHealth =CalculateHealth(target);           
|[3] 返回更新过健康值的游戏角色

returnnewGameCharacter(newHealth,
this.location); |

}

publicbool IsAlive

{

get {
return health > 0; }

}

// Other methods and properties omitted

}

在 C# 中,我们可以明确地把字段标记为不可变,用 readonly 关键字,这样,就不能改变字段的值;但是,如果该字段指向非不可变的类[ 即,引用可变类 ],目标对象仍然可以修改。要创建真正不可变的类,需要确保所有字段都被标记为 readonly,且字段的类型都是基本类型、不可变的值类型,或其它不可变的类。

根据这些条件,GameCharacter 类是不可变的,其所有的字段都用 readonly 限定符标记[1],int 是不可变的基本类型,Point 是不可变的值类型。当字段是只读时,值只能在创建对象时才可以设置,因此,我们只能在构造函数中设置角色的位置与健康值[2]。这样,对象初始化之后,就不能修改它的状态。那么,当操作需要修改游戏角色的状态时,我们该怎么做呢?

当你看到 HitByShooting 方法时,就知道答案了[3],它实现了游戏中对开枪的反应。它使用 CalculateHealth 方法(不在此示例中)来计算角色新的健康值。用命令式风格,这需要修改角色的状态,但这里是不可能的,因为类型是不可变的。相反,这个方法创建了GameCharacter 新的实例,表示修改后的角色,作为结果返回。

前面示例中的类,是不可变的 C# 类的典型设计,我们在书中一直使用这个示例(有一些修改)。现在,我们已经知道了不可变类型的表象,有必要了解一下其影响。

1.4.2 理解使用不可变性的代码

时间: 2024-10-25 14:32:51

1.4.2 理解使用不可变性的代码的相关文章

关于JS中原型链中的prototype与_proto_的个人理解与详细总结(代码示例+高清无码大图!——自备瓜子花生)

一直认为原型链太过复杂,尤其看过某图后被绕晕了一整子,今天清理硬盘空间(渣电脑),偶然又看到这图,勾起了点回忆,于是索性复习一下原型链相关的内容,表达能力欠缺逻辑混乱别见怪(为了防止新人__(此处指我)__被在此绕晕,图片就放在末尾了.) 以下三点需要谨记 1.每个对象都具有一个名为__proto__的属性: 2.每个构造函数(构造函数标准为大写开头,如Function(),Object()等等JS中自带的构造函数,以及自己创建的)都具有一个名为prototype的方法(注意:既然是方法,那么就

理解Web应用程序的代码结构和运行原理(3)

1.理解Web应用程序的运行原理和机制 Web应用程序是基于浏览器/服务器模式(也称B/S架构)的应用程序,它开发完成后,需要部署到Web服务器上才能正常运行,与用户交互的客户端是网页浏览器. 浏览器负责显示来自服务器的数据和接受用户的输入数据,也称为"与用户交互":服务器负责处理浏览器的访问请求,并把处理结果(数据或消息)组织成浏览器可以识别的格式文本返回. Web应用程序的主要特点如下: 1)浏览器主动请求服务器资源.在Web应用程序中,一般是浏览器首先向服务器发起访问某个网页或某

从源码理解Spring原理,并用代码实现简易Spring框架

前言(本文为原创,转载请注明出处) 个人之前对于框架的学习,就停留在配置,使用阶段.说实话过段时间就会忘得荡然无存.也不知道框架的运行逻辑,就是知道添加个注解,就可以用了. 由于实习,时间比较多,也感恩遇到个好老师,教并给我时间看源码,虽然没有做过多少业务,但是感觉比做业务更有意义.慢慢的去跟代码, 对Spring 运行流程大致有个解.现分享给大家,不足之处,希望各位补充,相互学习. 从源码看Spring 可能我们很少在意,ClassPathXmlApplicationContext这个类,其实

KMP算法的理解,伪代码,c代码实现

1.字符串问题形式化定义:假设文本是一个长度为n的T[1..n],而模式是一个长度为m的数组P[1..m],其中m<=n,如果有T[s+1..s+m]==P[1..m],那么就称模式P在T中出现.s为有效偏移,否则称为无效偏移. 2.方法:首先基于模式进行预处理,然后找到所有有效偏移(匹配). 几种方法的预处理时间和匹配时间 算法 预处理时间 匹配时间 朴素算法 0 o((n-m+1)*m) 有限自动机 o(m|所有有限长度字符串的集合|) o(n) KMP o(m) o(n) Rabin-ka

彻底理解线程同步与同步代码块synchronized

1 public class Demo { 2 public static synchronized void fun1(){ 3 } 4 public synchronized void fun2(){ 5 } 6 public static void main(String args[]) throws Exception{ 7 synchronized(xxx) { 8 9 } 10 } 11 } 三种同步类型 虽然写法不同,但实际上,只有一种,就是[同步代码块].这是核心核心核心.同步方

关于泛型,什么是泛型,如何理解泛型,直接上代码举例

泛型是JDK5中引入的特性,它提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型,就不至于在运行时出现转换异常, 它的本质是参数化类型(即以任何类型 T 作为参数,<T>,在使用时可以传入类型T的具体值 t ). 也就是将类型由原来的具体类型用参数T表示(即类型参数化),然后在使用/调用时传入具体的类型.这种参数类型可以用在类.方法和接口中,分别被称 为泛型类.泛型方法.泛型接口 . 版权声明:本文为CSDN博主「timon777」的原创文章,遵循 CC 4.0 BY-SA 版权

有用函数编程

<序> 感谢 关于本书 关于封面 第一部分 学习函数式思维 第一章 不同的思维 1.1 什么是函数式编程? 1.2 通往有用函数编程之路 1.3 用函数式编程提高生产力 1.3.1 函数范式 1.3.2 声明式编程风格 1.3.3 了解程序的执行 1.3.4 设计并发友好的应用程序 1.3.5 函数风格怎样形成代码 1.4 函数式编程演示样例 1.4.1 用声明式风格表达意图 1.4.1.1 用 LINQ 处理数据 1.4.1.2 用 XAML 描写叙述用户界面 1.4.1.3 声明式函数动画

半深入理解Java属性继承

前几天在面试的时候又被问到了一个问题,“Java重写和重载有什么区别?”.这个问题在Java领域是一个老生常谈的问题了,事实上我认为这两个东东除了中文名长得很像以外(英文名好像也很像),基本就没半毛钱关系了.我们很难找出他们的共性,却一直要尝试找出他们之间的区别,呵呵. 然而本文的主题并非重写和重载,而是重写的的孪生兄弟,属性继承. 故事的开始,我们先看一段代码 1 public class Parent{ 2 public String color; 3 public Parent(){ 4

深入理解CSS中的层叠上下文和层叠顺序(转)

by zhangxinxu from http://www.zhangxinxu.com 本文地址:http://www.zhangxinxu.com/wordpress/?p=5115 零.世间的道理都是想通的 在这个世界上,凡事都有个先后顺序,凡物都有个论资排辈.比方说食堂排队打饭,对吧,讲求先到先得,总不可能一拥而上.再比如说话语权,老婆的话永远是对的,领导的话永远是对的. 在CSS届,也是如此.只是,一般情况下,大家歌舞升平,看不出什么差异,即所谓的众生平等.但是,当发生冲突发生纠葛的时