旅游

面向对象编程的弊端是什么?

from : http://zingson.com/72.html弊端是,没有人还记得面向对象原本要解决的问题是什么。1、面向对象原本要解决什么?(或者说有什么优良特性)似乎很简单,但实际又很不简单:面向对象三要素封装、继承、多态。(警告:事实上,从业界如此总结出这面向对象三要素的一刹那开始,就已经开始犯错了!)。封装:封装的意义,在于明确标识出会访问某个数据结构(用面向对象的术语来说就是 类成员变量)的所有接口。有了封装,就可以明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者;而外部调用者也可以知道自己不可以碰哪里。这就提供一个良好的合作基础——或者说,只要接口这个基础约定不变,则代码改变不足为虑。继承+多态:继承和多态必须一起说。一旦割裂,就说明理解上已经误入歧途了。先说继承:继承同时具有两种含义:其一是继承基类的方法,并做出自己的扩展——号称解决了代码重用问题;其二是声明某个子类兼容于某基类(或者说,接口上完全兼容于基类),外部调用者可无需关注其差别。再说多态:基于对象所属类的不同,外部对同一个方法的调用,实际执行的逻辑不同。很显然,多态实际上是依附于继承的第二种含义的。让它与封装、继承这两个概念并列,是不符合逻辑的。不假思索的就把它们当作可并列概念使用的人,显然是从一开始就被误导了。实践中,继承的第一种含义(实现继承)意义并不很大,甚至常常是有害的。因为它使得子类与基类出现强耦合。继承的第二种含义非常重要。它又叫“接口继承”。接口继承实质上是要求“做出一个良好的抽象,这个抽象规定了一个兼容接口,使得外部调用者无需关心具体细节,可一视同仁的处理实现了特定接口的所有对象”——这在程序设计上,叫做归一化。归一化使得外部使用者可以不加区分的处理所有接口兼容的对象集合——就好象linux的泛文件概念一样,所有东西都可以当文件处理,不必关心它是内存、磁盘、网络还是屏幕(当然,如果你需要,当然也可以区分出“字符设备”和“块设备”,然后做出针对性的设计:细致到什么程度,视需求而定)。归一化的实例:a、一切对象都可以序列化/toStringb、一切UI对象都是个window,都可以响应窗口事件。——必须注意,是一切(符合xx条件的)对象皆可以做什么,而不是“一切皆对象”。后者毫无意义。显然,归一化可以大大简化使用者的处理逻辑:这和带兵打仗是类似的,班长需要知道每个战士的姓名/性格/特长,否则就不知道该派谁去对付对面山坡上的狙击手;而连长呢,只需知道自己手下哪个班/排擅长什么就行了,然后安排他们各自去守一段战线;到了师长/军长那里,他更关注战场形势的转变及预期……没有这种层层简化、而是必须直接指挥到每个人的话,累死军长都没法指挥哪怕只是一场形势明朗的冲突——光一个个打完电话就能把他累成哑巴。软件设计同样。比如说,消息循环在派发消息时,只需知道所有UI对象都是个window,都可以响应窗口消息就足够了;它没必要知道每个UI对象究竟是什么——该对象自己知道收到消息该怎么做。合理划分功能层级、适时砍掉不必要的繁杂信息,一层层向上提供简洁却又完备的信息/接口,高层模块才不会被累死——KISS是最难也是最优的软件设计方法,没有之一。总结:面向对象的好处实际就这么两点。一是通过封装明确定义了何谓接口、何谓接口内部实现、何谓接口的外部调用者,使得大家各司其职,不得越界;二是通过继承+多态这种内置机制,在语言的层面支持归一化的设计,并使得内行可以从代码本身看到这个设计——但,注意仅仅只是支持归一化的设计。不懂如何做出这种设计的外行仍然不可能从瞎胡闹的设计中得到任何好处。显然,不用面向对象语言、不用class,一样可以做归一化的设计(如老掉牙的泛文件概念、游戏行业的一切皆精灵),一样可以封装(通过定义模块和接口),只是用面向对象语言可以直接用语言元素显式声明这些而已;而用了面向对象语言,满篇都是class,并不等于就有了归一化的设计。甚至,因为被这些花哨的东西迷惑,反而更加不知道什么才是设计。2、人们以为面向对象是什么、以及因此制造出的悲剧以及闹剧误解一、面向对象语言支持用语言元素直接声明封装性和接口兼容性,所以用面向对象语言写出来的东西一定更清晰、易懂。事实上,既然class意味着声明了封装、继承意味着声明了接口兼容,那么错误的类设计显然就是错误的声明、盲目定义的类就是无意义的喋喋不休。而错误的声明比没有声明更糟;通篇毫无意义的喋喋不休还不如错误的声明。除非你真正做出了漂亮的设计,然后用面向对象的语法把这个设计声明出来——仅仅声明真正有设计、真正需要人们注意的地方,而不是到处瞎叫唤——否则不可能得到任何好处。一切皆对象实质上是在鼓励堆砌毫无意义的喋喋不休。大部分人——注意,不是个别人——甚至被这种无意义的喋喋不休搞出了神经质,以至于非要在喋喋不休中找出意义:没错,我说的就是设计模式驱动编程,以及如此理解面向对象编程。误解二、面向对象三要素是封装、继承、多态,所以只要是面向对象语言写的程序,就一定“继承”了语言的这三个优良特性。事实上,如前所述,封装、继承、多态只是语言层面对良好设计的支持,并不能导向良好的设计。如果你的设计做不出真正的封装性、不懂得何谓归一化,那它用什么写出来都是垃圾。误解三、把软件写成面向对象的至少是无害的。要了解事实上是什么,需要先科普几个概念。什么是真正的封装?——回答我,封装是不是等于“把不想让别人看到、以后可能修改的东西用private隐藏起来”?显然不是。如果功能得不到满足、或者未曾预料到真正发生的需求变更,那么你怎么把一个成员变量/函数放到private里面的,将来就必须怎么把它挪出来。你越瞎搞,越去搞某些华而不实的“灵活性”——比如某种设计模式——真正的需求来临时,你要动的地方就越多。真正的封装是,经过深入的思考,做出良好的抽象,给出“完整且最小”的接口,并使得内部细节可以对外透明(注意:对外透明的意思是,外部调用者可以顺利的得到自己想要的任何功能,完全意识不到内部细节的存在;而不是外部调用者为了完成某个功能、却被碍手碍脚的private声明弄得火冒三丈;最终只能通过怪异、复杂甚至奇葩的机制,才能更改他必须关注的细节——而且这种访问往往被实现的如此复杂,以至于稍不注意就会酿成大祸)。一个设计,只有达到了这个高度,才能真正做到所谓的“封装性”,才能真正杜绝对内部细节的访问。否则,生硬放进private里面的东西,最后还得生硬的被拖出来——当然,这种东西经常会被美化成“访问函数”之类渣渣(不是说访问函数是渣渣,而是说因为设计不良、不得不以访问函数之类玩意儿在封装上到处挖洞洞这种行为是渣渣)。一个典型的例子,就是C++的new和过于灵活的内存使用方式之间的耦合。这个耦合就导致了new[]/delete[]、placement new/placement delete之类怪异的东西:这些东西必须成对使用,怎么分配就必须怎么释放,任何错误搭配都可能导致程序崩溃——这是为了兼容C、以及得到更高执行效率的无奈之举;但,它更是“抽象层次过于复杂,以至于无法做出真正透明的设计”的典型案例:只能说,c++设计者是真正的大师,如此复杂的东西在他手里,才仅仅付出了如此之小的代价。(更准确点说,是new/delete和c++的其它语言元素之间是非正交的;于是当同时使用这些语言元素时,就不可避免的出现了彼此扯淡的现象。即new/delete这个操作对其它语言元素非透明:在c++的设计里,是通过把new/delete分成两层,一是内存分配、二是在分配的内存上初始化,然后暴露这个分层细节,从而在最大程度上实现了封装——但比之其它真正能彼此透明的语言元素间的关系,new/delete显然过于复杂了)。这个案例,可以非常直观的说明“设计出真正对外透明的封装”究竟会有多难。接口继承真正的好处是什么?是用了继承就显得比较高大上吗?显然不是。接口继承没有任何好处。它只是声明某些对象在某些场景下,可以用归一化的方式处理而已。换句话说,如果不存在“需要不加区分的处理类似的一系列对象”的场合,那么继承不过是在装X罢了。封装可应付需求变更、归一化可简化(类的使用者的)设计:以上,就是面向对象最最基本的好处。——其它一切,都不过是在这两个基础上的衍生而已。换言之,如果得不到这两个基本好处,那么也就没有任何衍生好处——应付需求变更/简化设计并不是打打嘴炮就能做到的。了解了如上两点,那么,很显然:1、如果你没有做出好的抽象、甚至完全不知道需要做好的抽象就忙着去“封装”,那么你只是在“封”和“装”而已。这种“封”和“装”的行为只会制造累赘和虚假的承诺;这些累赘以及必然会变卦的承诺,必然会为未来的维护带来更多的麻烦,甚至拖垮整个项目。正是这种累赘和虚假的承诺的拖累,而不是所谓的为了应付“需求改变”所必需的“灵活性”,才是大多数面向对象项目代码量暴增的元凶。2、没有真正的抓到一类事物(在当前应用场景下)的根本,就去设计继承结构,是必不会有所得的。不仅如此,请注意我强调了在当前应用场景下。这是因为,分类是一个极其主观的东西,不存在普适的分类法。举例来说,我要研究种族歧视,那么必然以肤色分类;换到法医学,那就按死因分类;生物学呢,则搞门科目属种…… 想象下,需求是“时尚女装”,你却按“窒息死亡/溺水死亡/中毒死亡之体征”来了个分类……你说后面这软件还能写吗?类似的,我遇到过写游戏的却去纠结“武器装备该不该从游戏角色继承”的神人。你觉得呢?事实上,游戏界真正的抽象方法之一是:一切都是个有位置能感受时间流逝的精灵;而某个“感受到时间流逝显示不同图片的对象”,其实就是游戏主角;而“当收到碰撞事件时,改变主角下一轮显示的图片组的”,就是游戏逻辑。看看它和“武器装备该不该从游戏角色继承”能差多远。想想到得后来,以游戏角色为基类的方案会变成什么样子?为什么会这样?——你还敢说面向对象无害吗?——在真正明白何谓封装、何谓归一化之前,每一次写下class,就在错误的道路上又多走了一步。——设计真正需要关注的核心其实很简单,就是封装和归一化。一个项目开始的时候,“class”写的越早,就离这个核心越远。——过去鼓吹的各种面向对象方法论、甚至某些语言本身,恰恰正是在怂恿甚至逼迫开发者尽可能早、尽可能多的写class。误解四、只有面向对象语言写的程序才是面向对象的。事实上,unix系统提出泛文件概念时,面向对象语言根本就不存在;游戏界的精灵这个基础抽象,最初是用C甚至汇编写的;……。面向对象其实是汲取以上各种成功设计的经验才提出来的。所以,面向对象的设计,不必非要c++/java之类支持面向对象的语言才能实现;它们不过是在你做出了面向对象的设计之后,能让你写得更惬意一些罢了——但,如果一个项目无需或无法做出面向对象的设计,某些面向对象语言反而会让你很难受。用面向对象语言写程序,和一个程序的设计是面向对象的,两者是八杆子打不着的两码事。纯C写的linux kernel事实上比c++/java之类语言搞出来的大多数项目更加面向对象——只是绝大部分人都自以为自己到处瞎写class的面条代码才是面向对象的正统、而死脑筋的linus搞的泛文件抽象不过是过程式思维搞出来的老古董。——这个误解之深,甚至达到连wiki词条里面,都把OOP定义为“用支持面向对象的语言写程序”的程度。——恐怕这也是没有人说泛文件设计思想是个骗局、而面向对象却被业界大牛们严厉抨击的根本原因了:真正的封装、归一化精髓被抛弃,浮于表面的、喋喋不休的class/设计模式却成了”正统“!总结: 面向对象其实是对过去成功的设计经验的总结。但那些成功的设计,不是因为用了封装/归一化而成功,而是切合自己面对的问题,给出了恰到好处的设计。让一个初学者知道自己应该向封装/归一化这个方向前进,是好的;用一个面向对象的条条框框把他们框在里面、甚至使得他们以为写下class是完全无需思索的、真正应该追求的是设计模式,则是罪恶的。事实上,class写的越随意,才越需要设计模式;就着错误的实现写得越多、特性用得越多,它就越发的死板,以至于必须更加多得多的特性、模式、甚至语法hack,才能勉强完成需求。只有经过真正的深思熟虑,才有可能做到KISS。到处鼓噪的面向对象编程的最大弊端,是把软件设计工作偷换概念,变成了“就着class及相关教条瞎胡闹,不管有没有好处先插一杠子”,甚至使得人们忘记去关注“抽象是否真正简化了面对的问题”。

数据库设计原则

从@蔡学镛看到的数据库的一些设计原则,可以考虑考虑.梳理数据库时,你会很惊讶地发现,各种数据都被塞进数据库,所以做数据库梳理的第一步是把它们区分出来,我的区分方式是:核心数据、业务数据、核心缓存数据、业务缓存数据、Session 数据。核心数据及其缓存都要再根据领域(domain)来区分,业务数据及其缓存都要再根据业务(business)来区分。梳理数据库或设计数据存储时,可以考虑数据的属性:1. 访问频率 (高/中/低)2. 读写比 (只读/读多/读少)3. 重要性 (重要/普通/不重要)4. 保密性 (保密/普通/不需保密)5. 数据笔数 (多/一般/少)6. 数据体积 (大/中/小)7. 一致性要求 (强/中/弱)8. 热点现象 (强/中/弱)9. 索引方式 ( ____ )

double cookie验证

from: http://www.75team.com/archives/729什么是double cookie验证double cookie验证是利用cookie来验证请求合法性的一种方法。一个double cookie验证的url形如http://a.com?c=cookie向服务器请求的url带上cookie,服务器收到请求后,解析出url中的cookie和http请求带过来的cookie进行对比。如果一样就说明请求合法,不一样就可以判定请求非法。因为是用url中的cookie和http请求中的cookie进行验证,所以叫double cookie验证。验证原理url是客户端javascript生成的,javascript可以读取cookie。url可以从任意客户端访问,但是只有一个客户端的http请求带给服务器的cookie和url中的cookie是一致的。注意事项用来验证的cookie在每个客户端必须唯一用来验证的cookie不能是敏感信息。比如登录用户的token不能作为验证的cookie应用场景double cookie验证不能判断用户修改本地cookie然后再进行的访问。但是没有关系。举个应用场景。比如一个网站的 评分功能的请求是这样的http://a.com?score=100&id=10000如果有人把这个url发到网上,引诱其它用户来点击,那么就会生成大量的评分请求。这时就可以用double cookie验证了。因为很难让点击这个链接的人先修改本地cookie然后再点击链接使用建议有的同学喜欢把cookie做个变换,防止别人一眼看出来是用哪个cookie做的验证。没必要这样做,也不应该这样做。变换的方法一定会暴露在客户端验证的目的不是为了防止有意伪造对cooie做变换的方法如果不得当,可能会对cookie的结构造成依赖。如果哪天cookie的结构改变了,就会使验证代码失效,甚至报错。

jquery图片等比例缩小插件

胡天硕的点点滴滴 提醒文章的缩略图,会把原图缩略之后就给变形,比例失调了,使用max-height max-widthde 的属性,在IE下面失效,现在改用jquery插件的方式了,去除了原来的图片延时加载,与等比例缩小插件有冲突.使用也是简单的,加载js文件。http://x.libdd.com/farm1/6424fa/f55203fd/loadimage.js调用: //图片等比例缩放 $(".post-thumbnail img").LoadImage({ scaling : true, width : 170, height : 130, loadpic:"http://x.libdd.com/farm1/6424fa/c106a7b5/default.jpg" });首页可以看到效果,放一张哥们的“萌像”(他自己说的,我看就是呆)。

db2 substr语法

做代码迁移,要把oracle迁移到db2上面,遇到了substr的使用,老是报错.原因是oralce的substr的postion从0开始,而db2的substr的postion从1开始,这个设计有些不合常规了啊!程序猿数数的时候都是从0开始的啊!

德问:编程是一种艺术创作

启动PostgreSql远程连接

启动PostgreSql远程连接 PostgreSql安装后,默认是不允许远程连接的,需要进行一些配置。配置有两种办法,一种是界面配置,另外一种通过修改文件(界面配置也就是修改文件的)。界面配置方法: 打开pgAdmin,工具-服务器配置。 1.配置postgresql.conf 2.配置pg_hba.conf修改文件方法:1.修改PostgreSQL9.2datapostgresql.conf,将listen_addresses的值修改为’*’,监听所有IP。如下:listen_addresses = ‘*’2.修改PostgreSQL9.2datapg_hba.conf,将注释着IPV4的127.0.0.1修改数据库服务器IP,如下:TYPE DATABASE USER ADDRESS METHOD #IPv4 local connections: host all all 192.168.1.20/24 md5注:24对应服务器网关为255.255.255.0 32对应服务器网关为255.255.255.255 配置完成后,重启PostgreSQL服务。关于pg_hba.conf中的几个参数说明:TYPE DATABASE USER CIDR-ADDRESS METHOD # IPv4 local connections: host all all 127.0.0.1/32 md5 这里面的字段的含义是:连接类型、可用数据库名、使用者、DIDR地址、验证方法 一、TYPE可选择local或者host,分别区分只能本地,与可远程二、DATABASEall或者具体数据库的名字三、USERall或者指定用户的名字四、DIDR-ADDRESS这个是指地址与掩码,指示一个IP或者IP网段,格式 IP/掩码。掩使用小于等于32的正数来表示。 掩码24,表示255.255.255.0 说明高24位是1. 掩码32,表示255.255.255.255,说明高32位是1.即这个掩码只表示当前一个IP地址。 所以直接使用32来表示一个指定的IP。五、METHOD验证方法可以选择以下几个: reject :拒绝访问 md5 :以MD5作为hash编码 password :密码作为明文传输 krb5 :密码以krb5作为hash编码 trust :可信任的

强势推荐ANT小蚂蚁

之前就知道ANT这个小蚂蚁,一直没有用过,这两天,下了点功夫,写了一个ANT的脚本。功能还行,可以完成同步svn代码、编译代码、打包代码、上传、部署的功能。直接上干货,看代码。[code]#JDK homejdk.home=/opt/Java/jdk1.6.0_33#webapp namewebapp.name=pmeappproject.name=pmeapp#svnsvn.url=http://127.0.0.1:9344/svn/pmeapp/trunksvn.uname=dapengsvn.pwd=dapengpwd#warwar.exclude=war.exclude.classes=#ftpftp.server=127.0.0.1ftp.password=dapengpwdftp.userid=dapengftp.path=/opt/ftp/#sshssh.host=127.0.0.1ssh.path=/opt/tomcat6/webappsssh.pwd=dapengpwdssh.uname=dapeng#sshssh.path.webapp=/opt/tomcat6/webappsssh.server.bin=/opt/tomcat6/binssh.cmd.sshClean=rm -rf /opt/tomcat6/webapps/${webapp.name}/ssh.server.start=/opt/tomcat6/bin/startup.shssh.server.stop=/opt/tomcat6/bin/shutdown.sh[/code]另外一个是关键中的核心[sourcecode]<project basedir=’.’ default=’usage’ name=’${project.name}’> <!– =================================================================== –> <!– 下句是import进ant属性配置文件,properties文件里存放基本的配置变量. –> <!– 该变量可以在build.xml中直接引用. –> <!– =================================================================== –> <property file=’ant.properties’/> <!– =================================================================== –> <!– 以下的几个属性是系统自带的,初始了tstamp之后,它们就有值了 –> <!– ${DSTAMP} ${TSTAMP} ${TODAY} –> <tstamp/> <property name=’war.name’ value=’${webapp.name}’ /> <!– =================================================================== –> <!– Init –> <!– =================================================================== –> <target name=’init’> <echo message=’————————————-‘/> <echo message=’start ant build ${project.name} – ${DSTAMP}${TSTAMP}’/> <property name=’debug’ value=’off’/> <property name=’optimize’ value=’on’/> <property name=’deprecation’ value=’on’/> <!– java源文件路径 –> <property name=’src.dir’ value=’${basedir}/src’/> <!– jar包路径 –> <property name=’lib.dir’ value=’${basedir}/WebRoot/WEB-INF/lib’/> <!– webapp路径 –> <property name=’webapp.dir’ value=’${basedir}/WebRoot’/> <!– 准备源文件路径 –> <property name=’build.src’ value=’${basedir}/AntBuild/build’/> <!– 编译源文件路径 –> <property name=’build.dest’ value=’${basedir}/AntBuild/bin’/> <!– 准备webapp文件路径 –> <property name=’buildwar.dest’ value=’${basedir}/AntBuild/warsrc’/> <!– 打包war文件路径 –> <property name=’war.dest’ value=’${basedir}/AntBuild/war’/> <!– jre lib路径 –> <property name=’jre.lib’ value=’${jdk.home}/jre/lib’/> <!– 引用svn task文件,使用svn任务可以使用–> <typedef resource=’org/tigris/subversion/svnant/svnantlib.xml’ /> <!– 设置svn相关属性 –> <svnSetting id=’svn.setting’ svnkit=’true’ username=’${svn.uname}’ password=’${svn.pwd}’ javahl=’false’ /> <!– classpath –> <path id=’classpath’> <!–web.lib–> <fileset dir=’e:/lib’> <include name=’/*.jar’/> </fileset> <fileset dir=’${jre.lib}’> <include name=’/.jar’/> </fileset> <fileset dir=’${lib.dir}’>…

添加右键“用Sublime打开”

最近迷上了Sublime text2编辑器,用的是绿色版的,没有右键打开,模仿UE的右键注册表文件,改了下,支持Sublime text2右键打开文件。Sublime text2 相当的神器,推荐每一位程序猿们使用.Windows Registry Editor Version 5.00[HKEY_CLASSES_ROOTshellSublime]@="用Sublime打开"[HKEY_CLASSES_ROOTshellSublimeCommand]@=""D:\360云盘\Tools\Sublime Text 2.0 x64\sublime_text.exe" %1"

让java web支持cors

场景:&nbsp;&nbsp;&nbsp; 客户端发出http请求,服务端对客户端的http请求进行验证问题:&nbsp;&nbsp;&nbsp; 问题的表象是 从Chrome发出HTTP命令后,Chrome console中报 “Origin null is not allowed by Access-Control-Allow-Origin”错误。产生原因:&nbsp;&nbsp;&nbsp; 这是由于Browser的same origin policy 限制的缘故。简单来说,从HTML中发出XMLHttpRequest&nbsp; 请求时,Browser会做检查,如果发现Response中没有Access-Control-Allow-Origin Header或Access-Control-Allow-Origin Header Header的值与 HTML的 orgin 不同时,Browser会拒接绝该Response,Javascript就收不到该Response。 本地HTML的Origin是 null, 而Server端没有发出Access-Control-Allow-Origin Header Header给Browser,&nbsp; 所以会有了“Origin null is not allowed by Access-Control-Allow-Origin”错误。&nbsp;&nbsp;&nbsp;&nbsp;简单的说,就是由于客户端和服务端处于两个不同的域,相互之间是不允许通信的.&nbsp;&nbsp;&nbsp; 不同的域包含:1.静态文件向服务器请求 2.客户端和服务端域名不同 3.客户端和服务端端口不同 等等,个人理解总结的,不是很准确.解决办法:&nbsp;&nbsp;&nbsp; 事实上有一个W3C标准,Cross Origin Resource Sharing (CORS) 专门用来解决这个问题的。目前的主流Browser也有支持。CORS 在HTTP Message 加入几个Header, Browser和 Server可以利用这些Header来判断对方是否是安全,是否可以通信。&nbsp;&nbsp;&nbsp; http://enable-cors.org/&nbsp; 介绍了目前常用的服务器和技术的支持CORS的办法.其中对与JAVA Web,里面没提到.整理下让Java Web支持的办法.Java Web支持的办法:&nbsp;&nbsp;&nbsp; 使用CORS Filter 解决.&nbsp;&nbsp;&nbsp; 下载地址:http://software.dzhuvinov.com/cors-filter.html&nbsp;&nbsp;&nbsp;&nbsp;使用方法:http://software.dzhuvinov.com/cors-filter-installation.html&nbsp;&nbsp;&nbsp;&nbsp; 参考文章&nbsp;&nbsp;&nbsp; http://www.cnblogs.com/LevinJ/archive/2012/04/09/2439670.html 43 Things:CORSBuzzNet:CORSdel.icio.us:CORSFlickr:CORSIceRocket:CORSLiveJournal:CORSTechnorati:CORS