`
xielingjiang
  • 浏览: 32885 次
  • 性别: Icon_minigender_1
  • 来自: 上海
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

Java基础再学习之面向对象编程

阅读更多

面向对象,OO,这个在当今程序界已经是最流行的词,不管是业内还是业外,似乎都已自己的系统是面向对象语言写出来的为荣。总之,有事没事总是拿面向对象说是。
但我这里要讨论我对面向对象的看法。
什么是面向对象
这个问题已经老生常谈了,写了这么多年的java程序,我想没有人会对这个OO的定义说不上几句。
但是我要问难道用java写就面向对象,写个class定义就面向对象?还有论坛里面前几年一轮纷纷的所谓贫血/充血模型,我想无非就是在讨论什么是面向对象的问题。
我们知道面向对象是从面向过程的思路过来的。说白了就是一个世界观的问题。从原来C或者更早语言来说,面向过程就是说我们思考一个事情的解决方案的时候,我们的思路就是第一步怎么做,接着做什么,然后做什么,最后做什么,在特殊情况下又做什么。这叫做有条有理,是一个过程。也最接近人的思维方式,而且电脑也很容易理解和执行。例如:

do A1
do B1
do A2
do B2
do C1
do C2


好了,那为什么会出现面向对象呢?我想一个事物出现必然是带着解决一个问题来的。那面向对象解决的是什么问题呢?肯定是面向过程遇到了人的需求中解决不了或者花大力气才能解决的问题。比如web的出现,事情不再是原来想象的一步 一步就能清晰描述的。web的需求千变万化,如果都一个个用过程描述,那管理器来就麻烦了。而且也容易出错,不清晰。
好了,人们想到了另外一个思路,比如,把事情的参与者很多,我们让不同的参与者做他们该做的事情,然后让一个组织者把他们串起来。因此,面向对象的世界观就是,让A做自己的事情,让B做自己的事情,让C做自己的事情,然后让D来组织分发任务。如下

   D
___|___
|  |  |
A  B  C
|  |  |
A1 B1 C1
A2 B2 C2


这样,这个世界就形成了,A, B, C, D对象各司其职。不仅能解决单一的一件事情,还能根据组合选择不同路径解决不同的事情。
总之,面向对象是一种世界观,一个思维方式,这种思维方式能让我们站在更高的层去描述这个世界。
但是面向对象说起来简单,做起来却不是那么容易。事情总是说起来容易做起来难啊。

怎么样实现面向对象
我想主要是两方面的关键点,这也是这么多年java一直在讨论的问题。
第一,怎么实现才够一个对象,也就是说对象的职责怎么划分?
讨论最多的名词就是贫血/充血模型,这个在论坛里面可以搜到一大堆。
贫血模型无非就是说对象职责太少了,充血模型就是说往对象里面塞行为,让对象自己做自己本来该做的事情。就好比一个是婴儿你要帮她端屎端尿,做任何事情,因为她贫血无行为能力。另外一个就好比成人,该他做的事情就扔给他,让他自食其力。
我不能说那个好那个差,我想在不同场合需要不同的处理方式,比如我需要灵活性,我希望你的行为是受外部控制监督的,那么贫血模型在合适不过了,它只提供你要的东西,而不负责你怎么使用这个东西。
而在系统有些数据变动不大,数据的使用方式和行为是常识性的非变动逻辑的,ok,我们可以让他去按照规定流程去做,就像生产线上工人。
第二,对象之间怎么联系才够OO
人有时候很贱,明明是想让对象联系在一起,但是又怕对象间联系的太紧密了,要达到若即若离的境界。术语上叫解耦。
那怎么办?于是人们想到了很多模式,比如经典的23中设计模式。
模式很多,我想大部分也记不住谁是谁的模式。
但我这里要讲的是其实他们都是一个思想。
比如 A对象 和 B 对象要建立联系。
一般我们能想到的就是A <--> B
很明了,但是人总会问很多假如,假如A有很多种,A1, A2, A3...
那么B联系A的时候就要判断A到底是A1还是A2还是A3
即,

 B-->A1 or A2 or A3


是吧,B肯定会很烦。
于是我们想到能否在A1, A2, A3。。。中选个代表,让他来联系B就可以了,免得B受判断之苦。就像A1,A2,A3。。。都是一个部门的,那么就让经理ManagerA来管理这些A吧。外面想找哪个A就让ManagerA来负责好了。于是

A1/A2/A3--->ManagerA<-->B


这样即使再来个C要联系A,也可以这样,
A1/A2/A3--->ManagerA<-->C
以此类推,假如B也有多种,

A1/A2/A3--->ManagerA<-->ManagerB<--B1/B2/B3
A1/A2/A3--->ManagerA<-->ManagerC<--C1/C2/C3



因此我们得出一个结论,
在建立两个对象联系的时候,最好不要让对象直接建立联系,而是让他们之间建立一道隔离,这样就达到了我们说的若即若离的地方。
拿实际的例子来看,
web页面有很多,后面对应的处理器controller也有很多。
如果不注意对象解耦那么,我们就这么做:

页面1 --> 处理器1
页面2 --> 处理器2
页面3 --> 处理器3


于是我们的页面紧紧的跟代码紧密绑定,看起来好像也行得通。但是我们联系第一个关键点,这种方式使得对象的行为完全有自身控制,灵活性上受到严重控制。虽然在简单的web页面逻辑下这种方式是直来直往的,但是始终让我们这些爱问假如的工程师们觉得那相当的不美。:)
于是我们利用第二个关键点的理解,那就在页面对象和处理器对象之间加个隔离。我们可以叫他为Servlet和处理器Factory,于是

页面1/页面2/页面3---> Servlet <--> 处理器Factory --> 处理器1/2/3


其中servlet主要职责是负责页面1/2/3的组织,组织好了以后仍给处理器Factory
而处理器Factory很显然,主要负责不同的处理器的组织调用,就像一个经理一样。
就好比两个部门,高层经理与经理对话,无需员工与员工直接对话,这样在员工相对变动,经理相对不动的情况下能够使得事情能长久运作下去,而不至于在某个员工离职后而使得这个架构不稳定。

怎么样?是不是很美?其实我们很多常见的代码都蕴含着美,需要我们有发现美的眼睛:)
我们总结一下公式:

员工1/2/3 --> 经理X <--> 经理Y <-- 员工A/B/C


好了,我们在回顾一个23中设计模式,我们就很好理解里面的用意了。
创建型:解决员工怎么被经理创建出来的问题
比如
singleton模式--自管理独一份;
Factory模式-->经理要招聘一系列不同角色组合的员工(一个研发部门需要开发,测试,美工);
Abstract Factory模式--->不同经理需要招聘不同系列的不同角色组合的员工。
Builder模式--->经理要招聘的这个角色的员工很复杂,比如要招聘一个team leader,需要很多严格的面试和流程审批。那就造个builder来专门针对不同的team builder出不同的leader。
prototype模式-->很好理解,就是说招聘的这个员工很简单,只要按照现有员工的样子一模一样复制一份就可以了。

结构型:解决其他部门的经理来向当前经理提需求的结构模式,也就是说怎么使得两个部门建立connection的框架。
比如:
Adapter模式---> 不同的需求需要不同的员工组合,因此该经理也是够忙了,语法实现上因此因此会有很多if/else等选择。为了跟现有部门兼容,有两种方式,一种是让提需求的人来adapter我们,一种是让自己做很多adapter来适应不同的系统。总之一句话,就是事情多的时候招了很多经理助理。
bridge模式--->就是说需求方自己也不知道自己需要怎么做,即使我方想写个adapter来适应你也不行。那怎么办?那我们就先约定要做什么,这样我就知道应该需要哪几种角色的员工了。具体怎么做由各自自己来稍后决定好了,你我双方只要知道对方能干什么就行,也就是接口和实现分离。
composite模式--> 更进一步说,如果连要做什么也不知道的时候,我们也不知道你需要哪些角色的时候,我们就把我们经理组合进去,这样你要什么都可以,即使是要我们经理做的事情也可以(要容器或者容器里面的对象)
decorator模式-->很好理解,就是说你需要一个懂德语的开发人员,但是我们部门不能提供这样的员工,作为经理怎么办呢?那就把现在的员工培训包装一下或者把该开发人员跟一个临时的翻译绑定一下让他具有翻译的功能。
facade模式 ---> 就是说作为经理应该有个新闻发言人,让她来告诉外面本部门能干什么事情,不能干什么事情。
flyweight模式--->就是说在开发人员资源紧缺的情况下,经理只能让有些开发人员一起做两件以上的事情了。免得浪费,呵呵,这就是IT民工:)
proxy模式 ---> 就是说经理使用一个员工的时候可以是外包人员,所以需要通过代理模式(外包公司)来驱使他做事。

行为型:结构型解决了内外连接的框架,但是没有指明连接以后的行为是怎么样?也就是说我虽然找到了对的人,但是我还没想好怎么灵活的让这个对的人做对的事情,这就要对他们的行为进行设计

这个模式还是挺多的,也许行为相对于结构来说变数更多些。

visitor模式: 主要目的就是实现数据和行为分离。一个员工拥有技能,知识。对于技能和知识的操作却是可变的,需要外部的培训来visit,这个员工只要accept这个培训就可以了,至于怎么培训提高技能就让培训的老师来决定吧。代码里面就是

让 员工.accept(培训)。 然后 培训.do(this员工)就可以了


state模式: 对于某些特性,比如员工的心情,心情好的时候开发效率高,心情差的时候开发效率低,因此,员工的心情是一个内部状态,在不同状态下,工作方式也完全不同。因此对员工的行为只要记住两个状态就知道了行为,而根本不需要关心行为的具体。代码实现就是

让员工 在 【心情好状态】下工作,【心情好状态】.执行(this员工的工作)


strategy模式:上面的state模式就是说如果调用一种行为的时候行为受到内部的状态位控制,那么如果有这个的行为受到外部的某种力量控制着怎么办?那么我们就要考虑用这个策略模式,比如,一个开发人员可以java编码,C编码,还可以perl编码,那怎么控制到底用那个编码方式呢?那就是在分配给这个开发人员工作的时候告诉他用那种编码策略。
注意这个跟上面的state不同的地方是这个特性不是这个员工的特性。可以理解为外部状态:)
command模式:上面策略模式说的是一种行为的执行行为的选择。但是如果对于一个员工来说,编码知识他的一种技能,可能他也需要吃饭,需要睡觉,需要谈女朋友的技能。所以如果经理要让一个员工分配任务的时候,不必亲自监督他完成任务为止,只要告诉员工一个命令,比如睡觉,员工就根据这个命令找到身体里面的相应的睡觉处理器说睡觉。
这样是不是把行为请求者和行为实者现分离了?
当然这个模式的前提是行为拥有者有行为注册的能力。这样才能map过去。
Observer模式:刚才之考虑行为的输入,没有说行为结束以后怎么告诉别人行为的结果。
一般情况下就是调用者等待行为执行完毕才继续做其他行为。但是这样就很浪费时间了。比如经理让员工编码,如果一定要等待这个员工编码完成才能指派下个任务那就惨了。所以我们只要让经理在指派一个观察员在这个开发人员旁边(睡觉也行),等开发完后,开发人员叫醒notify这个观察员,让这个观察员来通知指派任务的经理就可以了。
怎么样?省时又省力。NIO就是这么实现的。
Mediator模式:这个模式就是上面观察者的全集。举个例子,两个员工吵架了,他们之间直接合作的不可能了。这个时候需要找个中间人,让中间人来传递他们要的东西。呵呵:0
所以中介模式的前提是双方都得维护一个中介引用。
Memento模式:备忘录模式说白了就是一个记录历史的地方。比如一个员工编码的时候每到关键时刻都需要上传到一个库里面备忘,以便在以后编码工作的时候需要回滚到以前的一个版本去。
Iterator模式: 举个例子,一个开发过程不仅仅只是编码,可能还有测试,分析等。这个过程需要几个员工依次完成。但是我们又不需要让外面的人知道我们的开发流程是怎么样的。当然这个的前提是被迭代的员工必须具有相同或者相似的行为,比如他们都是IT人员。
还有只要指定开发模式即迭代模式(比如瀑布开发还是敏捷开发等),这样只要实现不同的迭代器就能实现整个流程的转换(可以说是策略模式)。
ChainofResponsibility模式:这个模式是上面迭代模式的补充,上面说迭代器可以指定这个被迭代者的调用顺序,但是这样还不够灵活,比如开发完了以后,需要指定测试的人,如果让迭代器指定,那么每次要制定一个新的测试的人的时候我还得重新写迭代器,所以与其这样我还不如让开发人员来指定测试,比如该开发暗恋其中的一个测试,那他就指定她来测试,
而她却喜欢那个他来部署,那就指定那个他为下一个节点。呵呵
因此执行起来就可以只要关心开发的执行就可以了,其他的就让他们自己形成一条责任链就可以了。
这样做的好处就是可以运行时指定行为。

interpreter 模式:就是说策略模式可以指定编码格式,让程序员写出不同的代码。而有些地方只要关心的是代码的执行结果。但是这些写出来的代码执行起来就需要不同的服务器,因此我们需要这些不同的解释器,解析器注册列表,当要解释的时候,只要挨个试着解析就行了。

Template模式:很好理解,就是说编码格式虽然指定了,但是代码风格必须统一,比如不管什么编程语言写的必须有注释,必须有设计文档等。至于怎么注释,每个编程语言都有自己的方法。


好了讲了这么多,说来说去其实就是一个宗旨:
对象的数据和行为最好分离。
对象的行为的联系最好隔离。

因此,以后
A需要调用B的服务的时候,最好在A和B之间建立一个BFactory之类的隔离。
A中除了与A独有的特性和行为以外,其他的外部相关的特性最好剥离出一个结构,其他的行为抽象出一个行为模式来。

 

0
1
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics