《必须知道的.net》读书笔记(一)

 

第一部分 渊源——.net与面向对象

第一章OO大智慧

1.1对象的旅行

1引言

对象与人类世界类比

2出生

new 分配内存

3旅程

CLR托管环境

在一定的约定和规则下,通过方法进行彼此的交互,从而改变本身状态。

4插曲

访问修饰符

继承

多态:接口实现,抽象类实现

5消亡

GC控制

6总结

类比,演化推进

 

第二章对象创建始末

对象的创建过程,内存分配分析,内存布局研究

1引言

new 内存分配和初始化

2内存分配

CLR内存区域包括

线程的堆栈:分配值类型实例,主要由操作系统管理,效率高,容量有限。

GC堆:用于分配小对象实例,对象实例小于85000字节

LOH堆:用于分配大对象实例。

 

IL指令解析

newobj

ldstr

newarr

box

2.1堆栈的内存分配机制

堆栈指针,地址由高到低;堆是由低到高

2.2托管堆的内存分配机制

托管堆是进程可用地址空间中的一块内存区域

托管堆也分为多个区域:垃圾回收堆(GC Heap),加载堆(Loader Heap)等。

GCHeap存储对象实例,受GC管理;

LoaderHeap存储元数据相关信息,就是Type对象,每个Type体现为一个MethodTable,MethodTable中记录元数据信息;不受GC控制。

TypeHandle:类型句柄,指向对应实例的方法表,对象创建时包含,占4字节。

SyncBlockIndex:用于线程同步,对象创建时包含,占4字节,指向一块SynchonizationBlock的内存块,用于管理同步对象。

NextObjPtr:托管堆维护的一个指针,下一个对象分配位置。

引用类型分配过程:

在堆栈分配引用指针,占4字节;

计算类型及父类字节总数,还要加上附加成员字节数8字节,内存按4字节的倍数进行分配;

搜索连续空间,GC只是把NextObjPtr向前推进相应字节,并清空当前范围内字节;

构造类型Type对象,存储在LoaderHeap;

初始化附件成员TypeHandle,指向LoaderHeap的MethodTable;SyncBlockIndex指向同步内存块;

通过构造器,进行实例字段的初始化;

实例字段存储顺序,父类在前,子类在后;

把托管堆地址赋值给栈上的引用指针变量;

2.3必要的补充

值类型嵌套引用类型,堆栈保存成员引用,引用类型分配在GC堆上;引用类型嵌套值类型,值类型作为实例分配在GC堆上。

MethodTable中的方法调用过程?通过TypeHandle找到MethodTable对应方法,再通过JIT Compiler编译为本地CPU指令,保存在动态内存中,然后在该内存地址执行。

静态字段内存分配:内存中只有一份,位于方法表的槽数组后,只能由静态构造函数初始化。

3结论

 

第3章继承

3.1什么是继承

继承,继承的实现本质,继承的分类与规则,继承与聚合,继承的局限

1引言

熟悉而又容易产生误解的话题

2基础为上

继承关系图

继承,就是面向对象中类与类之间的一种关系。继承的类称为子类、派生类,而被继承类称为父类、基类或超类。通过继承,使得子类具有父类的属性和方法,同时子类也可以通过加入新的属性和方法或者修改父类的属性和方法建立新的类层次。

继承机制体现了面向对象技术中的复用性、扩展性和安全性。

分为实现继承和接口继承。

这种在子类中实现虚函数的方式,称为方法的动态绑定,是实现面向对象另一特性:多态的基本机制。

通过继承我们轻而易举地实现了代码的复用和扩展,同时通过重载(overload)、覆写(override)、接口实现等方式实现了封装变化,隐藏私有信息等面向对象的基本规则。

3继承本质论

— 继承是可传递的,子类是对父类的扩展,必须继承父类方法,同时可以添加新方法。

— 子类可以调用父类方法和字段,而父类不能调用子类方法和字段。

— 虚方法如何实现覆写操作,使得父类指针可以指向子类对象成员。

— 子类不光继承父类的公有成员,同时继承了父类的私有成员,只是在子类中不被访问。

—  new 关键字在虚方法继承中的阻断作用。

用子类创建父类引用实例,调用方法原则:关注对象原则;执行就近原则。

4密境追踪

4.1实现继承与接口继承

— 抽象类适合于有族层概念的类间关系,而接口最适合为不同的类提供通用功能。

— 接口着重于 CAN-DO 关系类型,而抽象类则偏重于 IS-A 式的关系。 

— 接口多定义对象的行为;抽象类多定义对象的属性。 

— 如果预计会出现版本问题,可以创建“抽象类”。

— 因为值类型是密封的,所以只能实现接口,而不能继承类。

4.2聚合还是继承?

聚合分为三种类型,依次为无、共享和复合,其耦合度逐级递增。无聚合类型关系,类的双方彼此不受影响;共享型关系,Class2 不需要对 Class1 负责;而复合型关系,Class1 会受控于 Class2 的更改,因此耦合度更高。

聚合关系是一种 HAS-A 式的关系,耦合度没有继承关系高。

依赖关系表明,如果 Class2 被修改,则 Class1 会受到影响。

类与类之间的关系,通常以耦合度来描述,也就是表示类与类之间的依赖关系程度。没有耦合关系的系统是根本不存在的,因为类与类、模块与模块、系统与系统之间或多或少要发生相互交互,设计应力求将类与类之间的耦合关系降到最低。

而面向对象的基本原则之一就是实现低耦合、高内聚的耦合关系。

继承之毒瘤主要体现在:

— 继承可能造成子类的无限膨胀,不利于类体系的维护和安全。

— 继承的子类对象确定于编译期,无法满足需要运行期才确定的情况,而类聚合很好地解决了这一问题。

— 随着继承层次的复杂化和子类的多样化,不可避免地会出现对父类的无效继承或者有害继承。子类部分的继承父类的方法或者属性,更能适应实际的设计需求。

面向对象的基本原则

多聚合,少继承。

低耦合,高内聚。

Adapter 模式主要用于将一个类的接口转换为另外一个接口,通常情况下在改变原有体系的条件下应对新的需求变化,通过引入新的适配器类来完成对既存体系的扩展和改造。Adapter 模式就其实现方式主要包括:

— 类的 Adapter 模式。通过引入新的类型来继承原有类型,同时实现新加入的接口方法。其缺点是耦合度高,需要引入过多的新类型。

— 对象的 Adapter 模式。通过聚合而非继承的方式来实现对原有系统的扩展,松散耦合,较少的新类型。(新建一个Adapter对象,实现新接口,对象中加入原类的所有同名方法,根据引用父类参数调用实例子类的具体实现)

5规则制胜

— 密封类不可以被继承。

— 继承关系中,我们更多的是关注其共性而不是特性,因为共性是层次复用的基础,而特性是系统扩展的基点。

— 实现单继承,接口多继承。

— 从宏观来看,继承多关注于共通性;而多态多着眼于差异性。

— 继承的层次应该有所控制,否则类型之间的关系维护会消耗更多的精力。

— 面向对象原则:多组合,少继承;低耦合,高内聚。

6结论

所有的类型都最终继承自共同的根 System.Object 类。继承是.NET 运行机制的基础技术之一。理解继承、关注封装、品味多态、玩转接口是理解面向对象的起点。

 

第4章封装的秘密

1引言

面向对象的封装特性,字段赏析,属性赏析

在面向对象三要素中,封装特性为程序设计提供了系统与系统、模块与模块、类与类之间交互的实现手段。封装为软件设计与开发带来前所未有的革命,成为构成面向对象技术最为重要的基础之一。

2什么是封装?ATM

隐藏内部实现,提供对外接口。

3秘密何处:字段、属性和方法

— 类的功能是什么?

— 哪些是字段,哪些是属性,哪些是方法?

— 对外提供的公有方法有哪些,对内隐藏的私有变量有哪些?

— 类与类之间的关系是继承还是聚合?

字段(field)通常定义为 private,表示类的状态信息。,只读字段只能在构造函数中被赋值。

对字段公有化的操作,会引起对数据安全性与可靠性的破坏,封装的第一个原则就是:将字段定义为 private。

属性(property)通常定义为 public,表示类的对外成员。

属性的实质其实就是在编译时分别将 get 和 set 访问器实现为对外方法。

方法(method)封装了类的行为,提供了类的对外表现。在封装原则中,有效地保护内部数据和有效地暴露外部行为一样关键。

谁为公有、谁为私有,取决于需求和设计双重因素,在职责单一原则下为类型设计方法,应该广泛考虑的是类本身的功能性,从开发者与设计者两个角度出发,分清访问权限就会水到渠成。

4封装的意义

(1)字段通常定义为 private,属性通常实现为 public,而方法在内部实现为 private,对外部实现为 public,从而保证对内部数据的可靠性读写控制,保护了数据的安全和可靠,同时又提供了与外部接口的有效交互。这是类得以有效封装的基础机制。

(2)通常情况下的理解正如我们上面提到的规则,但是具体的操作还要根据实际的设计需求而定,例如有些时候将属性实现为 private,也将方法实现为 private 是更好的选择。

(3)从内存和数据持久性角度上来看,有一个很重要但常常被忽视的事实是,封装属性提供了数据持久化的有效手段。因为,对象的属性和对象一样在内存期间是常驻的。

(4)在面向对象中,封装的意义还远不止类设计层面对字段、属性和方法的控制,更重要的是其广义层面。我们理解的封装,应该是以实现 UI 分离为目的的软件设计方法,一个系统或者软件开发之后,从维护和升级的目的考虑,一定要保证对外接口部分的绝对稳定。不管系统内部的功能性实现如何多变,保证接口稳定是保证软件兼容、稳定、健壮的根本。

— 隐藏系统实现的细节,保证系统的安全性和可靠性。

— 提供稳定不变的对外接口。因此,系统中相对稳定部分常被抽象为接口。

— 封装保证了代码模块化,提高了软件的复用和功能分离。

5封装规则

— 尽可能地调用类的访问器,而不是成员,即使在类的内部。

— 内部私有部分可以任意更改,但是一定要在保证外部接口稳定的前提下。

— 将对字段的读写控制实现为属性,而不是方法,否则舍近而求远,非明智之选。

— 类封装是由访问权限来保证的,对内实现为 private,对外实现为 public。

— 封装的精华是封装变化。开发者应从设计角度和使用角度两方面来分析封装。我们将系统中变化频繁的部分封装为独立的部分,这种隔离选择有利于充分的软件复用和系统柔性。

6总结

包装的内外分为两个空间,对内实现数据私有,对外实现方法调用,保证了数据的完整性和安全性。

 

第5章多态的艺术

多态,动态绑定,面向对象

1引言

多态:可以呈现不同形式的能力或状态。

而在.NET 中,多态指同一操作作用于不同的实例,产生不同运行结果的机制。

2问题的抛出

万能加载器

3最初的实现

面向结构和过程的实现

4多态-救命的稻草

对象的开放封闭原则:对扩展开放,对修改关闭。

5随需而变的业务

只要有更合理的设计与架构,在基于面向对象和.NET 框架的基础上,完全可以实现类似于插件的可扩展系统,并且无需编译即可更新扩展。

6多态的类型、本质和规则

6.1分类

多态分为四类:强制的、重载的、参数的和包含的。

1)基类继承式多态

IS-A

2)接口实现式多态

CAN-DO

6.2多态的运行机制

是.NET 的动态绑定机制成就了面向对象的多态特性。一般以继承和虚方法来实现。

6.3多态的规则和意义

例必须显式地通过 virtual 或者 abstract 标记为虚方法或者抽象方法

此继承和重载是多态的实现基础

 

第6章接口

接口,接口映射本质,面向接口编程,.net的接口

1引言

接口,是面向对象设计中的重要元素,也是打开设计模式精要之门的钥匙。

2什么是接口

所谓接口,就是契约,用于规定一种规则由大家遵守。

接口是一组行为规范。

实现接口还意味着,同样的方法对不同的对象表现为不同的行为。

3.Net中的接口

1)接口多继承

2)接口的本质

接口本质上仍然被标记为.class,同时提供了 abstract virtual 方法 MyMethod,因此接口其实本质上可以看作是一个定义了抽象方法的类,该类仅提供了方法的定义,而没有方法的实现,其功能由接口的实现类来完成。

接口在本质上,仍旧是一个不能实例化的类,但是又区别于一般意义上的类,例如不能实例化、允许多继承、可以作用于值类型等。

3)由string想到的,框架类库的典型接口

4面向接口的编程

表示对接口编程而不要对实现编程,更通俗的说法是对抽象编程而不要对具体编程。

按照接口隔离原则,接口应该被实现为具有单一功能的多个小接口,而不是具有多个功能的大接口。

5接口之规则

— 接口隔离原则强调接口应该被实现为具有单一功能的小接口,而不要实现为具有多个功能的胖接口,类对于类的依赖应建立在最小的接口之上。

— 接口支持多继承,既可以作用于值类型,也可以作用于引用类型。

— 禁止为已经发布的接口,添加新的成员,这意味着你必须重新修改所有实现了该接口的类型,在实际的应用中,这往往是不可能完成的事情。

— 接口不能被实例化,没有构造函数,接口成员被隐式声明为 public。

— 接口可以作用于值类型和引用类型,并且支持多继承。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值