变化与不变.
应对变化之道.变化,修改,扩展更方便.
不变的共性才可复用.
越抽象越有共性
,易复用
,越具体越有差异.
功能越单一越
可复用.
越稳定的越可复用.
把复杂的地方分解提炼成类?
易变的地方.
资源:职责,你要完成职责,你
拥有相应的权力以及资源,这些完全由你支配.
过程,你不独立拥有支配
.
资源,要么全局共享
,要么
作为参数
临时借用.
对象具有组织结构
.
2,3个人的工作室.大家把资源放在公共的地方,谁用谁去拿,用完了
还回去.
或者找正在用的人要.
20,30人,有专人负责专门的资源.用时找其登记,用完归还.
8 |
// 定义被转化的字符串常量指针 |
9 |
const char * lpcszS = ” 测试用例 ” ; |
10 |
int nLen = 0 ; |
11 |
|
12 |
// 指向保存UNICODE字符集缓冲区的指针 |
13 |
wchar_t * lpwcsBuffer = NULL ; |
14 |
|
15 |
// 指向保存ASCII/GBK字符集缓冲区的指针 |
16 |
char * lpszBuffer = NULL ; |
17 |
int nStrLength = 0 ; |
18 | |
19 |
// 设置语言环境 |
20 |
_tsetlocale(LC_ALL, _T( ” zhi ” )); |
21 | |
22 |
// 调用API进行ASCII/GBK向UNICODE字符集转换 |
23 | |
24 |
// 第1步:获取保存转换结果缓冲区长度 |
25 |
nLen = MultiByteToWideChar( |
26 |
936 , // 代码页 |
27 |
0 , // 附加标志, 此处填0, 取Windows默认值 |
28 |
lpcszS, // 要转换的字符串指针 |
29 |
– 1 , // 要转换的字符串长度, 此处填-1, 表示由函数自行测量 |
30 |
NULL , // 存放结果的缓冲区指针, 填NULL表示本次仅测量转换结果长度, 不做实际转化 |
31 |
0 // 存放结果的缓冲区长度, 填0表示本次仅测量转换结果长度, 不做实际转化 |
32 |
); |
33 | |
34 |
// MultiByteToWideChar返回0表示函数调用错误, 否则返回转换结果缓冲区长度 |
35 |
if (nLen = = 0 ) { |
36 |
_tprintf(_T( ” 转换失败, 错误代码 %d ” ), GetLastError()); |
37 |
} else { |
38 |
|
39 |
// 第2步:分配内存 |
40 |
if (lpwcsBuffer = ( wchar_t * )malloc(nLen * sizeof ( wchar_t ))) { |
41 | |
42 |
// 第3步:转化。再次调用MultiByteToWideChar函数, |
43 |
// 此时参数5为指向上一部分配缓冲区的指针, 参数6为缓冲区长度 |
44 |
MultiByteToWideChar( 936 , 0 , lpcszS, – 1 , lpwcsBuffer, nLen); |
45 |
wprintf(L ” 转换结果 %s ” , lpwcsBuffer); |
win32api中
这类代码不少见.可能有一点重要的考虑:尽量使用由用户分配的内存,
而非系统的分配内存,
否则系统所使用的内存
可能很快耗尽.
用户内存耗尽只影响一个
程序.系统内存耗尽影响系统中运行的所有程序.
win32是基于c语言的
.当然c语言也可以模拟对象.
如果
是我们自己的程序且使用C++.很显然在类似场合:使用string
引用更方便,
不用调用两次api.
面向对象关心职责与服务划分,该
谁
去做,做什么.怎么做是由做的人去关心的细节.
更像领导.
OO:一件事是由相关的对象分工合作完成.
一个系统中的对象及其职责相对来说更稳定.变化更局部.
而面向过程:
关心产品怎么做.更像基层员工
.一件事是由很多步骤完成的.一方面,有时一个步骤
的变化,引起相关步骤的变 化.另一方面,过程之间的交互,状态的保持,要么参数,要么是全局变量.全局变量谁都可以修改.而对象对此进行了封装.函数实现功能复用,对象实现职责复用,抽象层次更高.
就像人有思
维
模式
一样.
可以用同样的
做事的方法,
做不同的事.
交互模式:
对象间的交互:以
消息.
面向过程:以数据为核心,围绕数据.数据在各个
函数间流动.输入,处理,输出.
世界500强的领导跳槽很多跨行.领导才能更通用.
而专业技术人员跳槽比较少跨行.专业细节太多.
就像一个公司.公司架构相对变化比较少,公司产品可能变化比较大.架构相应的是职责.生产产品也是一种职责,但生产什么,怎么生产会变化.铁打的营盘,流水的兵.
使用面向对象的思维方法,其实是一个把业务逻辑从具体的编程技术当中抽象出来的过程,而这个抽象的过程是自上而下的,非常符合人类的思维习惯,也就是先不考虑问题解决的细节,把问题的最主要的方面抽象成为一个简单的框架,集中精力思考如何解决主要矛盾,然后在解决问题的过程中,再把问题的细节分割成一个一个小问题,再专门去解决细节问题。
因而一旦牢牢的抓住了这一点,你就会发现在软件设计和开发过程中,你自己总是会不知不觉的运用面向对象的思维方法来设计和编写程序,并且程序的设计和开发也变得不再那么枯燥,而一个合理运用面向对象技术进行设计和架构的软件,更是具备了思维的艺术美感。
举例:
签字.
用两种编程的方式来实现:“我吃饭”这个事件
这是一个很简单事件,我简要的分析了一下:
从面向过程的角度:
首先有一个函数(或者说是动作),那就是吃,然后有两个数据成员:我和饭。然后再在一个函数体里面实现这个算法。
从面向对象的角度:
首先分析发现其中有两种数据,人和饭,这样就产生了两个对象,进而抽象为两个类,然后发现人有一个方法:吃。最后产生一个人类类型的变量我,然后就可以实现这个算法。
如果我们有一种高级语言或者也可以说是直接用伪代码来实现的话,他们各自的伪代码就可以用下面的方式来表示:
面向过程代码:
{
我,饭;// 完成吃这个函数的两个变量
吃{a,b};// 定义一个函数来实现吃这个过程或者说是动作
吃{我,饭};//或者是 吃{饭,我};主要取决于函数内部的实现是a吃b,还是b吃a
}
面向对象代码:
我{
吃()};// 产生一个类我,实现一个方法:吃
饭{ }; // 产生另一个类,饭
我
.
吃(饭);// 类我的一个变量我调用方法吃,对饭进行操作。
我们从这里就可以很明显看出面向对象和面向过程之间的区别了,面向过程更倾向于事件,他主要是先产生一个事件的核心,中文中其实就是表示动作的动词,然后设定变量来完成这个动作。而对于面向对象,则更接近于现实,他是首先找到其中的数据成员,也就是所谓的万物,找到后万物皆对象,在对每个对象分析找到各自所包含的方法(也就是面向过程中各个对象可以实现的函数或者说是动作)。相比之下后者更容易建模和进行系统设计,尤其是在大型系统的设计中。
如果把这个问题引申或者进一步思考,就可以得到关于面向对象的进一步理解的或者是对其全貌的概览。
之前的事件改为:我吃面,牛吃草,然后还会反刍。
这个时候我们发现对象就有我,牛,面,草。其中我的动作(即方法,为了通俗理解,这里不再使用面向对象的术语)就有吃,牛则是有吃和反刍。我们分析还可以发现其实我和牛就在这个事件的条件下具有相同点,都是动物,都要吃,而面和草对于这个问题中也是具有相同点的,他们都是食物。但是这里为了表现更多的信息,我们不构造食物类。
同样我们用伪代码来实现的话,这个事件的伪代码就可以用下面的方式来表示:
动物 {
吃();
}; // 构造一个动物类,可以实现一个方法:吃
牛 extends 动物 {
吃();
反刍;
} // 构造一个新的类牛继承自动物类并且覆写了动物类的方法吃,而且还有一个属于自己的方法,反刍。
我extends 动物 {
吃();
} // 构造一个新的类我继承自动物类并且覆写了动物类的方法吃,此
时牛和我的吃的方法就实现了多态
面{
} //这里没有将面和草构造在一个食物类里,这样是可以的,但是在这里
意义不大,相反还会增加代码量
草{
}
我
.
吃(面); //直接创建一个我的类型的变量调用吃这个方法实现对面这个类类型
的一个变量的操作
牛
.
吃(草); //直接创建一个我的类型的变量调用吃这个方法实现对面这个类类型
的一个变量的操作
牛
.
反刍(); //牛类类型的变量实现了一个空的方法反刍。
上面的例子基本上就实现了面向对象编程的一个概述,其中牛和草之间只有吃与被吃的关系,他们之间的只是通过一个实例变量来实现练习,这样就把牛和草的其他信息都封装起来了。
谈面向对象的思维方式:
这个标题有点大..我能说多少说多少..因为我也是个菜鸟..如果其中有些理解跟您有出入..还望指教..有争议才可以进步:)..
1、新手为什么总抱怨面向对象编程(以下简称OOP)难学??
2、新手为什么总无法深刻的理解OOP的思想??
3、能写出一个合格的类就代表你理解了OOP的思想了吗??
4、什么样才算真正的理解了OOP??
5、OOP难在什么地方??为什么我总是学不会??
相信很多人和我一样..在学习OOP的时候总会有上面那么多的问题..不过不要紧.我们今天就来探讨一下这些问题..
我个人认为..很多人都认为会写一个类就理解了OOP的思想了…这个思路是错误的..这就是为什么很多人虽然会写类了..但是写出来的类很“畸形”..究其根源..还是因为没有深刻的理解OOP的思维.
我建议大家..努力学习OOP基础..先不要去尝试写一个值得骄傲的类..你扪心自问..你虽然可以写出一个优秀的类.但是你理解了OOP了吗??
现在对于广大的PHPer来说..一个非常困难就在眼前..不光是我们这些菜鸟..就连一些著名的开源程序也一样..对于OOP非常不明确..
根据我的理解.我觉得大部分人写出”畸形”的类还是对OOP没有理解的非常深刻..那么好..今天我们大家就来探讨一些这个问题…
我们首先得知道.
这个世界为什么会有OOP.为什么会出现OOP
..一个事物从出现到发展.到今天的大红大紫..肯定有它无可替代的优越性..
这种优越性
经过这么多年的发展…很
有必要普及到每个程序员
..因为作为一名程序员.一定要有这样的思想..你的程 序不是写给你自己的..你的程序是写给他人甚至后人看的..一段优美的代码也许一个程序员一生只能写出一段.但是这段代码也许会对以后发生惊人的意义.. 所以建议大家以后写代码.不要为了赶时间.不要为了着急实现某项功能..希望大家
仔细锤炼代码
..仔细思考..这对于你本人也是一种提高..
其次我们得理解为什么程序最初是
面向过程的
..也就是为什么会先有C而不是先有C++..好像这是个人类学的问题.或者说是一个哲学问题..人类思 考问题是按照
某一种过程的
..这一个过程的结束也许可以发生一个质的改变..因为时间是这个空间不可缺少一个维度.所以他决定了事物都是按照一个过程发展进行的..所以从这个角度来说..面向对象于面向过程并不冲突的..其实面向对象是
一种思维方式
.而不是一种
处理事务的过程
..
为什么会出现面向对象呢??
这个也得从人类的认知说起..因为人们逐渐发现了..这个世界是
可以总结出来的
..人们为了更好的判断事物.总是自觉或者不自觉的在
给事物进行归类
..这种归类的过程就是人们对面向对象的思维的一种认识.一种学习.一种进步..
人们会
把水果放在一起储藏
..再
把肉类放在一起储藏
..水果中又把
容易变质的放在一起
..这些不自觉的行为当被上升为理论的时候..这个强大的面相对象的就出现了..
一切皆对象.这句话果真不错..我目前还没有发现这个世界上不是”对象”的一种事物..你能找到吗??你理解这句话吗??噢对..貌似”时间”不是对象..那”时间”又是什么呢??这个需要跟霍金商量下吧..
我来具一些例子..我的Acer 4710就是笔记本的一个对象..
笔记本
这个笼统的概念又是从
一体机
发展而来的..而
一体机
又是根据我们平常所说的
台式机
发展而来的..
我们每个人都是人类的一个对象..太阳是恒星的对象..地球是行星的对象..等等等等..总之..我们每天都会接触无数的对象..每天都在不自觉中使用面向对象的思想..
(所属关系,还是并列关系,还是对应关系?)
那么好.一个最难解释的问题来了..你说
一切皆对象没错..那么这跟我们写程序有什么关系呢??如何跟我们的程序发生联系呢??
其实是非常容易被解释的..你可以想象一下..我们程序员写的程序..一般来说.都是
为了解决某个实际问题的
..而这个实际问题就可以被牵扯到N多个对象..比如用户登陆..一个用户登陆他就是一个对象..
那么好.问题又来了..这个
比起我们面向过程的编程方式有什么区别呢??我们为什么要使用面向对象的编程方式呢?
这个问题问的非常好..以致于一些书籍都没有解释..说到这里我BS一下市面上N多的OOP的书籍..大部分都是你抄我我抄你..没有一点创新.. 这些OOP书籍用了大部分篇幅讲了
如何封装.如何多态.如何重载.如何继承.讲了类和接口等
等等等..但是往往新手最迷茫的OOP的思维方式却很少提 到..这里我再插一句..人云亦云总是可气的..现在很多OOP书籍费大力气讲如何封装.什么叫闭包等等的概念..学完到后来我才发现..
OOP
是开放 的.是一种思维方式
..封装并不是OOP必须的..人们大夸其辞得描述封装时OOP的三大特点之一.是不得不掌握的内容是非常重要非常重要的内容..我实 在不敢恭维..依照我的理解..OOP是一种思维方式..封装是这个大思维方式下的一种扩展..当我们接触到了
JavaScript
的面相对象的特性
后..当我们接触到
面向切面的思维方式
后..封装是不是又变得不是那么重要了呢??引用Exceed PHP论坛上面仁兄的一句话.
说到OO,每个人都会联想到类的封装,
所有教科书也是这么强调着写的。。。。。
很少有人关注类也是应该有开放性的。
好了.我们就不再为这个问题纠缠了..我们回到上面的问题上..
为什么要选择OOP
.
这个确实值得每个人去思考..而且这个问题到现在为止.没有一个准确的答案..有不少大牛也在争论这个问题..我们今天是为了学习OOP而探讨这个问题的.所以我们就抛开争论..
其实这个问题也非常好回答..为了提高
代码的层次性
.提高
代码的重用性
.减少
代码的耦合性
..这些很官调的话我们很难理解.为什么??很不幸.我的回答是.因为我们是PHPer..
这里我们举个例子..今天我特意去查询了下
所有的UML工具
..令人失望的是.这其中的大部分工具全部是for Java或者C++的.即使是有PHP的也是一种扩展的形式存在的..目前我还没有见到过一种专门for PHP的UML工具存在..扯开UML和语言有没有直接的关系不说(UML跟语言真的没关系吗??)..这个现象我们需要思考下.为什么PHP这么遭人唾 弃..但是又为什么从google查询PHP的结果要比Java多N倍.为什么??
我想.这个原因大概就是我们所说PHP是一种”草根”语言..
我并没有半点鄙视PHPer的意思..因为我本人本身也是名PHPer..大部分的PHPer都是单干..正因为PHP的灵活.所以单干的比较 多..而且效率很高..没几天就可以做出一个引以自豪的项目..很少是一个大型的团队..所以很多人根本没有体会到提高代码的层次性有什么好处..也更难 体会到OOP的好处..这也就是为什么OOP在PHP中这么难被理解..也更难被运用到项目中了..
而Java就不同了.Java大多是大公司运用的项目.所以几十人的团队是经常的事情..
但是PHP真的就比Java更”草根”吗??
我想事实不是这样的..草根只有对于程序来而言的..PHP是自由的.是开放的.虽然他不严谨.但是他比较起Java更加灵活..比如Java要实现
面向切面
的编程..确实是不容易的..而PHP一个简单的runkit就可以搞定..而且我曾经看到一个人在寻求在Java中如何实现PHP的魔术方 法..这是我们PHPer很引以为自豪的事情..所以不要再认为PHP是草根语言..
PHP是足够强大到胜任今天的每一个Web项目的
..只要你有优秀的策划..难道FaceBook不是一个很好的例子吗??
如果你一个人做一个项目你会怎么办??直接上来就敲代码吗??在一个项目中..策划要占很大的比例..策划的时候要对系统的
各个部分的可行性
进行分 析报告..要对系统的
各个功能
进行建模..对于Web来说.此时基本可以设定这个项目要写
哪几个类.哪个类都有什么样的功能
等等.
比如我们要做一个
用户注册登陆的简单的系统
..那么首当其冲的是要有一个
用户类
..这个类其中最起码的方法有addUser(用户注册) login(用户登录)..所以在项目策划的时候.我们就可以写一个接口..把这些方法定义为抽象方法..这就好像你是个小BOSS.然后你对手下说. 去.把addUser login这两个方法给我完成了..但是你手下并不总是那么听你话的..也许他们会偷懒忘掉一个.也许他们会写出来.但是方法名给你改了.比如改成了setUser userLogin..这对于一个团队来说.是一个非常头疼的事情..你这个小BOSS很难规划..你说的话他们都不听.你这个BOSS是不是有点名不副 其实??
还有另外一个好处..比如你离开这个公司了.但是你代码你是带不走了..所以以后的代码维护又要交给你的下一任了..这个人也许会选择修改你的代 码..但是如果他足够聪明是不会这么做的..他会
选择性的吸收你的代码
.比如你的代码 addUser 正是他想要的.但是你写的login已经不符合他的要求..所以他需要的是什么?对了.只需简单的覆盖即可..这样做的好处是没有修改一点你的代码.这是 因为指不定哪天你的代码
又会被又到
..这就是我们经常在SVN的段落注释中见到的那句话(如果到XX年XX月XX日这段代码还没有被用到.那么你就可以删 除)..这是个保险的行为..
其实OOP就是这点东西.是不是觉得我说的跟书上的还是很一样?没什么收获?不要紧.我们继续来.
为了真正的理解OOP.还需要代码的帮助..下面是一段Java代码
int a=5;
int b=6;
如果你已经理解OOP.你应该很惊讶的看出来.这其实就是一段非常具有OOP特征的代码..为什么这么说呢?
每个人几乎都知道a和b都是int类型..那么好我来出一道填空题.
a和b都是int的(__).
这里的括号里你会选择填什么?当然有了上面的铺垫.我相信你会填”对象”的..
填什么不要紧.最主要的是理解它..int这是具有一类的虚拟概念.就像鸟类一样.没有一直鸟的学名叫做鸟..1,2,3,5,6,7,4,23等等都是 int的一个对象.他们首先是属于int的..其次.他们又有了
自己的特征
..比如大小. 1比2小.2比0大..这样就产生了多态..多态其实很好理解..我们每个人就是人类多态的表现..如果没有多态那么这个世界就会很单调..没有这么丰富 多彩了..而且2还可以和1有些瓜葛.比如2=1+1..所以我们可以说
每个正整数都是继承自1
这个数字..总之.这些体现了OOP美妙的思维..(对关系何联系的解释)
再来看一段Java代码.
int test(int a);
这是一个没有方法体的方法..根据上面的理论.我们可以推断出.其实test这个方法也是int的一个对象..只不过他不是一个确定的数字.而
是一 个过程
..经过这个过程可以计算出一个数字..
反正最终还是
一个数字..再看里面的参数..比如我传进去一个2..那么好我问你.这个2是以什么方式传进 去..看.又是对象吧..
所以来说..其实对象的思想你一直在用.就是没被注意..以后你需要一段时间.可能很长..尽量用这种思想去思考问题..
面向对象是一种思维方式..是一种积极解决问题的途径..
这里就出现了现在大部分PHPer包括我在内的这样一群人..这些人都刻意的为了OOP而去OOP..
这些人自认为对OOP已经很了解..所以时常的去研究OOP如何编程.如何写出一个漂亮的类.如何对类进行漂亮的封装..如何对类进行继承..接口是怎么运用的等等..总在这些问题上纠缠..越纠缠越晕乎.越晕乎越对OOP不了解..至此就变成恶性循环了..
如果真正的理解OOP的思想后..你的思维方式也许就会发生一些改变..
也许以后的你..看问题将会更加全面..
我再次重申
面向对象是一种思维方式..它不仅对我们写程序大有好处..甚至对你处理现实中的问题上.对你的自身修养上都会有很大的提高.