封装和抽象

关注侧重点不同
数据抽象,关注的是数据类型及作用于这些数据类型对象上的操作

封装主要关注的是,这些操作是否对外部可见



我的理解是这样的:
抽象就是把相同的东西提取出来,包括数据和方法。
封装就是确定哪些是public哪些是private和protected。


在《 代码大全》中的第5章有解释,而在第6章作者有更详细的介绍。
虽然还是没有直接给出抽象与封装的直接定义。但是给出了它们关注的侧重点不同。
6.1节---抽象数据类型(ADT)
ADT是指一些数据以及对这些数据所进行的操作的集合。

一个准则是,当我们在操作数据的时候,不应该用对象直接对数据进行访问,我们应该使用与数据对应的那些操作去操纵数据。
而这些操作(子程序)如果对于外部可见,就是类的公开接口。
而公开接口就是一种抽象,它避免了我们在数据结构的低层次上操纵数据。

6.2节---良好的类接口下的小节---良好的封装
封装是一个比抽象更强的概念。抽象通过提供一个可以让你忽略实现细节的模型来管理复杂度,而封装强制阻止你看到细节。这两个概念之所以相关,是因为没有封装时,抽象往往容易被打破。

综合6.1和6.2我们可以看到。
我们在定义一个类的时候,设计了类的数据成员(private),方法,并规定了哪些方法public,哪些方法private,这个过程本身既包括了抽象,也包括了封装。
如果一定要进行一个划分,那么 将数据,方法整合到一个类里面,并且希望使用者只使用方法去操作数据成员,而且希望哪些方法应该被类使用者调用,这就是是抽象
然后在此基础上, 物理上规定哪些成员为public,哪些成员为private,这就是封装

所以作者说的, 让我们在不同层次上处理细节。我的理解是:
假如说有一个聚会人员名单,你使用一个queue来保存每一个报名者,那么你对人员的增删就需要对于这个queue来操作。这是具体的数据结构层次。
如果你抽象为ADT,那么使用者就对聚会人员这个对象直接add(某人),或者delete(某人)这样的操作,使用者也不知道是用vector,还是queue,还是stack来存的。

作者说的, 封装填补了抽象留下的空白。我的理解是:
封装保证了抽象想要达到的目的的实现。因为封装在抽象的基础上,规定了public,private强制规定了可见性。这就是填补了空白的意思。

以下为转载:

今天在总结最近一个项目的时候,突然灵感一现,理解了一些以前困惑的问题,和自己一直以来的设计上的问题,这里来分享下。

  抽象与封装,是我们在做设计和写程序的时候经常用到的,然而很多时候抽象封装的不对则会造成很乱、很遭的设计。在我最近的项目里就很有体会。场景是这样的,有一个新闻表单,用户填写然后提交,程序要做的就是检查数据(包括是否合法,是否为空等),如果没有错误就向数据库中插入一条数据,如果验证不通过则通过弹窗的方式提示用户,然用户继续输入。然后对于实现就是下面这样的:

 

try
{
    // 验证数据
    $bean->validate()
}
catch (BeanException $e)
{
    // 通过弹窗的方式提示用户
    halt_js($e->getMessage();
}
// 获取验证后的数据
$post = $bean->get_array();
// 插入一条数据
$db->insert($table, $post);

  但是发现除了这个表单,其他的表单都是这样的,发现这是重复代码,老是需要复制粘贴,于是就想把它用一个类,或者函数给封装起来,这样每次调用就方便了。就产生了下面的代码:

   
   
$beanDB -> insert( $table , $data );

 

然后在insert中就做了上面的验证并提示的功能,但是后来有这么一个需求,我需要一份bean验证后的数据,这个时候问题就来了,因为在这个新的封装类中就没办法获取到了;后来又来了一个需求提示方式要换了,因为是ajax的方式来提交的,这个时候也没办法了,马上就感觉头大起来了,而且,对于这么一堆乱代码,自己头也很晕,不知道这个封装到底是什么意义,就发生了厌恶之感,不太愿意去写了。

  出现这种结果的原因在于错乱的抽象与封装,对于封装还仅仅停留在代码的层次上,看到重复的代码就用一个函数包装起来,这样维护起来就很痛苦了,因为第一,当需求变化影响到这个封装的时候由于事先考虑的东西很少,只是因为这段重复的代码就封装了,很难应对需求的变化,而且加上这个封装没有在概念上形成一种意义的话,对你理解代码没有帮助,于是维护问题就出来了。

  所以我认为在做任何抽象和封装的时候,我们都应该是先从概念上来考虑,从概念的层次进行抽象,封装。比如像刚刚那个问题,首先考虑为什么这段代码是重复的,从概念上讲,它们都做了这几个动作,第一就是验证数据,第二就是出错用一种方式进行提示,成功就将验证后得到的数据插入。而之前的需求都是这样的,所以不会有什么问题,一旦我的步骤不是这样的时候就会出问题了,比如,我成功后不是立马将验证数据插入,先留下来一份我要用,然后这个时候再插入,就会没办法满足了。当我们从概念上理解这段代码后,我们就要进行抽象和封装,我们要封装的是这个做事的流程,抽象出来的就是这么一段流程,$beanDB就需要验证部分,需要提示部分,需要插入数据部分,而这每个部分都是可以随时更换的,这样当需求变化的时候我们就可以很方便的应对了,这个时候我们想到设计模式中,对于流程的封装就是模板方法,然后对于想更换显示方式,就想到策略方式了,用这两种设计模式就可以解决这个问题了。

  在项目中还有个很严重的问题,在一个插入数据方法里放了太多的东西,以至于我都不敢再去调用它了。因为做项目的时候根本就没考虑清楚就开始写了,开始的时候就想这是一个向数据库插入数据的方法,但是当插入数据要做的事情多起来的时候,我就不断的给它加入新的代码,破坏了封装和抽象,同样是犯了上面说到的问题,没有从概念上考虑它到底是什么,应该负有什么责任,就随便的给它加代码,破坏了概念上的封装。于是就会遇到和上面一样头疼的维护问题。

  所以总结了一下后发现,在做设计的时候,我们都应该是针对概念进行抽象和封装,把概念弄清楚了,程序就很好写了,而且当变化来的时候,由于你之前考虑过这个概念,不要去动这个概念,那么不会发生严重的问题,头也不会很晕,不知道这个东西到底是什么了。而且如果是抽象出的概念,它的复用性也会更强,会加大系统的复用,提高可维护性。



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值