1.3.2 让ATM告诉你,什么是封装
那么,封装究竟是什么? 首先,我们考察一个常见的生活实例来进行说明,例如每当发工资的日子小王都来到ATM机前,用工资卡取走一笔钱为女朋友买礼物,从这个很帅的动作,可以得出以下的结论: — 小王和ATM机之间,以银行卡进行交互。要取钱,请交卡。 — 小王并不知道ATM机将钱放在什么地方,取款机如何计算钱款,又如何通过银行卡返回小王所要数目的钱。对小王来说,ATM就是一个黑匣子,只能等着取钱;而对银行来说,ATM机就像银行自己的一份子,是安全、可靠、健壮的员工。 — 小王要想取到自己的钱,必须遵守ATM机的对外约定。他的任何违反约定的行为都被视为不轨,例如欲以砖头砸开取钱,用公交卡冒名取钱,盗卡取钱都将面临法律风险,所以小王只能安分守己地过着月光族的日子。 那么小王和ATM机的故事,能给我们什么样的启示?对应上面的3条结论,我们的分析如下: — 小王以工资卡和ATM机交互信息,ATM机的入卡口就是ATM机提供的对外接口,砖头是塞不进去的,公交卡放进去也没有用。 — ATM机在内部完成身份验证、余额查询、计算取款等各项服务,具体的操作对用户小王是不可见的,对银行来说这种封闭的操作带来了安全性和可靠性保障。 — 小王和ATM机之间遵守了银行规定、国家法律这样的协约。这些协约和法律,就挂在ATM机旁边的墙上。 结合前面的示例,再来分析封装吧。具体来说,封装隐藏了类内部的具体实现细节,对外则提供统一访问接口,来操作内部数据成员。这样实现的好处是实现了UI分离,程序员不需要知道类内部的具体实现,只需按照接口协议进行控制即可。同时对类内部来说,封装保证了类内部成员的安全性和可靠性。在上例中,ATM机可以看做封装了各种取款操作的类,取款、验证的操作对类ATM来说,都在内部完成。而ATM类还提供了与小王交互的统一接口,并以文档形式——法律法规,规定了接口的规范与协定来保证服务的正常运行。以面向对象的语言来表达,类似于下面的样子:
1 namespace InsideDotNet.OOThink.Encapsulation
2 {
3 /// <summary> /// ATM类 /// </summary>
4 public class ATM
5 {
6 #region 定义私有方法,隐藏具体实现
7 private Client GetUser(string userID) {}
8 private bool IsValidUser(Client user) {}
9 private int GetCash(int money) {}
10 #endregion
11 #region 定义公有方法,提供对外接口
12 public void CashProcess(string userID, int money)
13 {
14 Client tmpUser = GetUser(userID);
15 if (IsValidUser(tmpUser)) { GetCash(money);
16 }
17 else
18 { Console.Write("你不是合法用户,是不是想被发配南极?"); }
19 }
20 #endregion
21 } /// <summary> /// 用户类 /// </summary>
22 public class Client { }
23 }
在.NET应用中,Framework封装了你能想到的各种常见的操作,就像微软提供给我们一个又一个功能不同的ATM机一样,而程序员手中筹码就是根据.NET规范进行开发,是否能取出自己的钱,要看你的卡是否合法。 那么,如果你是银行的主管,又该如何设计自己的ATM呢?该以什么样的技术来保证自己的ATM在内部隐藏实现,对外提供接口呢?