连载:面向对象葵花宝典:思想、技巧与实践(11) - “封装” 详解

封装的概念本身很好理解,意思就是把一堆东东装起来。

 

但要想真正理解封装,这样还远远不够。

第一个问题是:我们要封装什么?

这个问题很好回答,封装当然是封装不想让别人知道或者看到的东东了。

例如:

你的身家。。。。。。

漂亮MM的年龄。。。。。。

富二代的女朋友数。。。。。

明星是否整过容。。。。。。

你是如何赚到100万的(想想什么样的赚钱方法不想让人知道?)。。。。。。

你是如何消磨时间的(想想什么样的消磨时间方法不想让人知道?)。。。。。。

等等

站在面向对象的角度来说,封装就是“类”的一个功能,你可以封装“类”的属性(比如身家、年龄等),也可以封装“类”的方法(比如说如何赚钱、如何消磨时间),也就是说,面向对象通过“类”来实现了封装。

  

第二个问题是:我们为什么要封装?

封装数据的主要原因是“保护隐私”,因为有“隐私”,所以要“封装”。如果没有封装,你的隐私就暴露在所有人面前了,别人也可以控制你的隐私,那样将是非常危险的。

 

例如面向过程的设计中,数据结构是公开的,任何能够获取到数据的人都可以随意修改,也可以使用不同的方式修改,如果某个不小心的程序员或者菜鸟或者一个准备离职又心怀不满的开发人员,无意或有意改错了,那么其它依赖这个数据的函数都会受到影响,要么导致业务出错,甚至导致程序崩溃。

 

而面向对象的类封装了属性后,对属性的修改只能通过类的方法进行,一来不会暴露内部的具体属性,二来对属性的操作都是统一的,不会出现乱改的情况。

 

封装方法的主要原因是“隔离复杂度”。每个类只需要关注自己的负责的功能如何完成即可,如果需要其它类配合,只需要调用类的方法即可,而不需要了解其它类功能的具体的实现。

 

“隔离复杂度”的例子即使在现实世界中也比比皆是。例如我们夏天常用的空调能够提供制冷功能,我们只要轻轻一按遥控器的按钮,空调就能够开始制冷,但空调究竟是如何制冷的,绝大部分人并不知道,也并不关心。空调封装了制冷的实现过程,对人提供了一个制冷的按钮,人通过这个按钮来启动制冷的过程。

 

【封装的样例】

简单的这么回答你可能没有什么感觉,但给一个面向对象“封装”和面向过程“无封装”的例子,相信你就很清楚了。

 举个简单的例子,假设用程序实现付款这个操作,我们来看面向对象和面向过程的方式。

 

面向过程 = 算法 + 数据结构

这里的数据结构是公开的,每个地方都可以看到和引用的,而且必须知道,否则面向过程的各个处理流程就没法处理了。

具体代码实现如下:

person.h

[cpp] view plaincopy

  1. #ifndef PERSON_H_  
  2. #define PERSON_H_  
  3.   
  4. typedef struct Person{  
  5.     char* name;  //姓名  
  6.     int money;   //金钱数量  
  7. }Person;  
  8.   
  9. #endif /* PERSON_H_ */  

money.c

[cpp] view plaincopy

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3.   
  4. #include "person.h"  
  5.   
  6. #define null 0x00  
  7.   
  8. int main(void) {  
  9.   
  10.     Person* me = (Person*)malloc(sizeof(Person));  
  11.     me->name = "华仔";  
  12.     me->money = 100;  
  13.   
  14.     //收银员收银  
  15.     if( me->money > 50 ){  
  16.         me->money -= 50;   //收银操作时,需要知道Person实际有多少钱,然后直接操作Person的money  
  17.         printf("%s 付款成功,共  %d 块\n", me->name, me->money);  
  18.     }  
  19.     else{  
  20.         printf("%s 付款失败 \n", me->name);  
  21.     }  
  22.   
  23.     //小偷偷钱  
  24.     printf("偷了 %s %d 块\n", me->name, me->money);  
  25.     me->money = 0;   //小偷也可以直接知道Person有多少钱,并直接操作Person的money  
  26.   
  27.     free(me);  
  28.     me = null;  
  29.     return EXIT_SUCCESS;  
  30. }  

也就是说,你有多少钱,所有人都知道!

也就是说,你的钱,别人可以随便控制!

就像你去超市买东西,付款的时候,收银员说:把你所有的钱摆在台子上,我从里面拿50.

不用我说你也知道,这当然是一件很恐怖的事情!

 

面向对象 = 对象 + 交互

但在面向对象的实现里面就不会这样了,你不需要把钱摆出来,你只需要拿出50就可以了,你既不需要担心别人知道你有多少钱(然后实施某种后续动作),也不需要担心别人拿错了(不管是有意的还是无意的)。

 

具体实现代码如下:

Person.java

[java] view plaincopy

  1. package com.oo.java;  
  2.   
  3. /** 
  4.  * 普通人 
  5.  */  
  6. public class Person {  
  7.   
  8.     private String _name;    //姓名  
  9.     private Integer _money;  //金钱  
  10.       
  11.     public String getName() {  
  12.         return _name;  
  13.     }  
  14.   
  15.     public Boolean pay(Integer money){  
  16.         //付款的逻辑由Person自己控制,例如判断当前的钱是否够支付  
  17.         if( money > _money ){  
  18.               
  19.             return false;  
  20.         }  
  21.           
  22.         _money -= money;  
  23.         return true;  
  24.     }  
  25. }  

Cashier.java

[java] view plaincopy

  1. package com.oo.java;  
  2.   
  3. /** 
  4.  * 收银员 
  5.  */  
  6. public class Cashier {  
  7.   
  8.     public Boolean get(Person person, Integer money){  
  9.         Boolean result = person.pay(money);  //收银员只需要调用Person的pay方法,无需知道Person当前有多少钱  
  10.         if( result ){  
  11.             System.out.println(person.getName() + " 付款成功,共  " + money +" 块");  
  12.         }  
  13.         else{  
  14.             System.out.println(person.getName() + " 付款失败");  
  15.         }  
  16.           
  17.         return result;  
  18.     }  
  19. }  

Thief.java

[java] view plaincopy

  1. package com.oo.java;  
  2.   
  3. /** 
  4.  * 小偷 
  5.  */  
  6. public class Thief {  
  7.   
  8.     public Boolean stole(Person person){  
  9.           
  10.         //小偷想直接访问Person的money,但这样做不允许,编译出错  
  11.         System.out.println("偷了 " + person.getName() +" " + person._money + " 块\n");  
  12.         person._money = 0;  
  13.           
  14.         //虽然小偷这个类语法上也可以直接调用Person的pay方法,  
  15.         //但Person的pay方法里面可以做很多的校验功能来让这样的调用返回失败  
  16.         person.pay(50);  
  17.     }  
  18. }  

================================================ 
转载请注明出处:http://blog.csdn.net/yunhua_lee/article/details/19611515
================================================ 

时间: 2024-12-04 16:30:42

连载:面向对象葵花宝典:思想、技巧与实践(11) - “封装” 详解的相关文章

Java面向对象编程中final关键字的使用方法详解_java

在Java中通过final关键字来声明对象具有不变性(immutable),这里的对象包括变量,方法,类,与C++中的const关键字效果类似. immutable指对象在创建之后,状态无法被改变 可以从三个角度考虑使用final关键字: 代码本身:不希望final描述的对象所表现的含义被改变 安全:final对象具有只读属性,是线程安全的 效率:无法修改final对象本身,对其引用的操作更为高效 final 变量定义final Object a,则a只能被初始化一次,一旦初始化,a的数据无法修

黑客攻击的11步详解及防御建议

  全世界网络面临巨大考验,每个人的信息都受到严重的安全威胁,尽管目前看起来你的信息还是有一定的安全保障,可是面对层出不穷的新技术,有必要了解整个攻击过程,因为黑客们依然存在. 安全公司Aorato的一项新研究显示,个人可识别信息(PII)和信用卡及借记卡数据在今年年初的Target数据泄露实践中遭到大规模偷窃后,该公司的PCI合规新计划已经大幅降低了损害的范围.利用所有可用的公开报告,Aorato的首席研究员Tal Aorato ery及其团队记录了攻击者用来攻击Target的所有工具,并创建

黑客攻击我们的 11 步详解及防御建议

安全公司Aorato的一项新研究显示,个人可识别信息(PII)和信用卡及借记卡数据在今年年初的Target数据泄露实践中遭到大规模偷窃后,该公司的PCI合规新计划已经大幅降低了损害的范围. 利用所有可用的公开报告,Aorato的首席研究员Tal Aorato 'ery及其团队记录了攻击者用来攻击Target的所有工具,并创建了一个循序渐进的过程,来讲述攻击者是如何渗透到零售商.在其网络内传播.并最终从 PoS系统抓取信用卡数据的.关于事故的细节依旧模糊,但是Be'ery认为,有必要了解整个攻击过

mysql中int(1)和int(11)区别详解

mysql字段定义中INT(x)中的x仅仅指的是显示宽度.该可选显示宽度规定用于显示宽度小于指定的列宽度的值时从左侧填满宽度.显示宽度并不限制可以在列内保存的值的范围,也不限制超过列的指定宽度的值的显示.所以x的定义与存储空间没有任何关系都是4个字节. 作为SQL标准的扩展,MySQL也支持整数类型TINYINT.MEDIUMINT和BIGINT.下面的表显示了需要的每个整数类型的存储和范围. 类型 字节 最小值 最大值     (带符号的/无符号的) (带符号的/无符号的) TINYINT 1

java语言学习002_面向对象编程思想

      人类在认识世界时,为了方便自己和智慧提升,很自然的对事物进行了分类.对世界进行了抽象,若把所有各个事物看做对象,纵观所有对象,这些对象具有各自的或共有的特征,并且又有共有的或各自的的能力,这样就可以对具有相同一些特征和一些能力的事物进行了归类.       比如,车,有汽车,火车他们都有哪些属性?                  汽车,特征:长度,颜色,速度,轮胎,载重,平面行走--能力:移动,载东西,--                  火车,特征:长度,颜色,速度,轮胎,载重

PHP带节点操作的无限分类实现方法详解_php技巧

本文实例讲述了PHP带节点操作的无限分类实现方法.分享给大家供大家参考,具体如下: 包含(移动多个节点:移动单个节点:删除多个节点:删除单个节点:新增节点),另附数据库表结构 一.db sql语句 //db used for php无限分类 create table tree( id int(10) not null primary key auto_increment, name varchar(255) not null, lft int(10) not null default 0, rg

详解PHP对数组的定义以及数组的创建方法_php技巧

传统上把数组(array)定义为一组有某种共同特性的元素,这里的共同特性包括相似性(车模.棒球队.水果类型等)和类型(例如所有元素都是字符串或整数)等,每个元素由一个特殊的标识符来区分,这称为健(key).请注意,上面这句话中的传统上一词,因为现在可以摒弃这种定义,数组结构中可以包括完全无关的元素.PHP则更进一步,数组中的元素甚至可以不属于同一种类型.例如,一个数组可能包含州名.邮政编码.考试成绩或扑克牌等元素. 每个实体包含两个项:前面提到的健(key)和值(value).可以通过查询键来获

面向对象编程依赖注入详解_java

说说依赖注入 在面向对象编程中,我们经常处理处理的问题就是解耦,程序的耦合性越低表明这个程序的可读性以及可维护性越高.控制反转(Inversion of Control或IoC)就是常用的面向对象编程的设计原则,使用这个原则我们可以降低耦合性.其中依赖注入是控制反转最常用的实现. 什么是依赖 依赖是程序中常见的现象,比如类Car中用到了GasEnergy类的实例energy,通常的做法就是在Car类中显式地创建GasEnergy类的实例,并赋值给energy.如下面的代码 interface E

PHP编程中的__clone()方法使用详解_php技巧

可以在对象类中定义一个__clone()方法来调整对象的克隆行为.此方法的代码将在克隆操作期间执行.除了将所有现有对象成员复制到目标对象之外,还会执行__clone()方法指定的操作.下面修改Corporate_Drone类,增加以下方法: function __clone() { $this->tiecolor = "blue"; } 之后,创建一个新的Corporate_Drone对象,增加employeeid成员的值,克隆这个对象,然后输出一些数据,从而显示克隆对象的tie