抽象和封装

二.抽象和封装
整理自 《java与模式》阎宏编著

1.关于抽象类
只要有可能,不要从具体类继承。
[img]http://eneasy.iteye.com/upload/picture/pic/10111/e4fd3f74-07f5-3207-8c55-378bf29cc57d.jpg[/img]
如图,在一个以继承关系形成的等级结构里面,树叶节点应该是具体类,而树枝节点应该是抽象类或接口。
抽象类应该拥有尽可能多的共同代码。
[img]http://eneasy.iteye.com/upload/picture/pic/10113/8b5a1db4-5b70-374b-b803-79e7e53a5b28.jpg[/img]
抽象类应该拥有尽可能少的数据。
[img]http://eneasy.iteye.com/upload/picture/pic/10115/9266af37-bf2e-3b59-973a-3184e1966d55.jpg[/img]
在一个继承的等级结构中,共同的代码应该尽可能的往等级结构的上方移动。把重复的代码从子类移到超类中,可以提高代码的复用率。一个对象从超类继承过来的代码,在不使用时不会造成对资源的浪费。
一个对象的数据,无论是否使用都会占用资源,因此数据应该尽量放到具体类或等级结构的低端。



2.对可变性封装原则
“找到系统的可变因素,将它封装起来”,称为可可变性封装原则,是实现“开-闭”原则的途径,与合成/聚集复用原则相辅相成。
抽象化与实现化的最简单实现,也就是“开-闭”原则在类层次上的最简单的实现,如下图所示:
[img]http://eneasy.iteye.com/upload/picture/pic/10117/c0de3df3-3b5a-36b6-a028-7bc0098f0f15.jpg[/img]
一般来说,一个继承结构中的第一层是抽象角色,封装了抽象的商业逻辑,这是系统中不变的部分。第二层是实现角色,封装了设计中会变化的因素。这个实现允许实现化角色有多态性变化。如下图所示:
[img]http://eneasy.iteye.com/upload/picture/pic/10119/f1842552-a91f-328d-87e6-9712b3da31c4.jpg[/img]
换言之,客户端可以持有抽象化类型的对象,而不在意对象的真实类型是“实现化”、“实现化1”、“实现化2”、“实现化3”。如下图所示:
[img]http://eneasy.iteye.com/upload/picture/pic/10121/89249b7c-b5ce-3774-ab52-6db4046ba417.jpg[/img]
显然,每一个继承关系都封装了一个变化因素,而一个继承关系不应当同时处理两个变化因素。换言之,这种简单实现不能够处理抽象化与实现化都面临变化的情况。如下图所示:
[img]http://eneasy.iteye.com/upload/picture/pic/10123/cf7bdb26-1132-300a-8282-5ec8b2a7f900.jpg[/img]
上图中的两个变化因素应当是彼此独立的,可以在不影响另一者的情况下独立演化。比如,下面的两个等级结构分别封装了自己的变化因素,由于每一个变化因素都是可以通过静态关系表达的,因此分别使用继承关系实现,如下图所示:
[img]http://eneasy.iteye.com/upload/picture/pic/10125/5510087b-9a01-36a2-95a5-fc3160d34c97.jpg[/img]
那么在抽象化与实现化之间的变化怎么办?
正确的设计方案应当是使用两个独立的等级结构封装两个独立的变化因素,并且在它们之间使用聚合关系,以达到功能复合的目的。自然地引导到桥接模式上面。如下图所示:
[img]http://eneasy.iteye.com/upload/picture/pic/10127/6e8e66f4-228a-37f2-9148-dd8aeae590d8.jpg[/img]
从另一个角度讲,一个好的设计通常没有多于两层的继承等级结构。或者说,如果出现了两个以上的变化因素,就需要找出哪一个变化因素是静态的,可以使用继承关系;哪一个变化因素是动态的,可以使用聚合关系。


3.接口
接口只定义了方法的特征,而没有给出具体的实现。由于接口没有给出任何实现,所以它比抽象类更为抽象。
接口是软件可插拨性(pluggable)的保证。
在一个类等级结构中的任何一个类都可以实现一个接口。这个接口会影响到此类的所有子类。此类不得不实现这个接口中所规定的方法,而其子类自动继承到这些方法,也可以置换掉这些方法(或者其中一些方法)。这时候,这些子类就具有了可插拨性。
关联的可插拨性:
一个对象需要完成一项任务,所以需要知道其它对象,并调用其它对象的方法。这个对象对其它对象的知识叫做关联。
如果一个关联不是针对一个具体的类, 而是针对一个接口,那么任何实现这个接口的类都可以满足要求。换句话说,当前对象并不在意关联的是那一个具体的类,而仅仅关心这个类是否实现了某个接口。
这样就可以动态地将这个关联从一个具体的类转换成另外一个具体的类,这么做的惟一条件是它们实现了相同的接口。
调用的可插拨性:
一个对象不可避免地调用其它对象的方法,这种调用不一定非得是一个具体的类,而可以是接口,这样一来,所以实现这个接口的具体类都可以被当前对象调用。而当前对象可以动态地决定调用哪一个具体类的实例。
因此接口提供了关联和方法调用的可插拨性,使得软件在灵活性,可扩展性,可插拨性得到了保证。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值