[TOC=1,2]
面向对象理论是面向对象编程的核心,但是我发现大部分Java程序员热衷于像单例模式、装饰者模式或观察者模式这样的设计模式,而并没有十分注意学习面向对象的分析和设计。学习面向编程的基础(如抽象,封装,多态,继承等)是非常重要的,而运用它们来设计干净的模块也同样重要。我也认识很多不同等级的程序员,他们没有听过这些面向对象理论,或者不知道某个设计理论有什么好处,或者如何在编码中使用这些设计理论。
我们起码要设计出高度一致而且松散耦合的代码。Apache和Sun的源代码就是学习Java面向对象理论的非常好的例子。JDK遵循了一些设计模式,譬如在BorderFactory中使用工厂模式,Runtime类中使用单例模式,java.io中的许多类中使用装饰者模式。如果你真的对Java编程感兴趣,请先阅读Joshua Bloch的Effective Java,正是他参与编写了Java API。另外两本我喜欢的关于设计模式的书还有,Kathy Sierra等编写的的Head First Design Pattern和Head First Object Oriented Analysis and Design。这些书帮助理解面向对象理论,并帮助我写出更好的代码。
学习任何设计理论或模式最好的方法就是现实世界中的例子,这篇文章只是要给还在学习阶段的程序员介绍面相对象理论。我想以下每一条都需要用一篇文章来详细介绍,我以后也会逐一介绍的,只是现在先来个快速浏览一下。
# 避免重复,DRY(Don’t repeat yourself)
面相对设计理论的第一条就是避免重复,不要写重复的代码,尽量将共同的功能放在一个地方。如果你准备在不同地方写同一段代码,那么只写一个方法。如果你不止一次硬编码某个值,那么将其声明成public final常量。这么做的好处就是容易维护。但是不要滥用这一条,重复不是指代码的重复,而是指功能的重复。譬如你有一段相同的代码来验证OrderID和SSN,但它们代表的意义并不相同。如果你将两个不同的功能合并在一起,当OrderID更改了格式之后,那么检验SSN的代码就会失效。所以要警觉这种耦合,不要将任何相似但不相关的代码合并在一起。
# 将变化封装起来
在软件领域唯一不变的就是“变化”。所以最好将你觉得将来会有改变的代码封装起来。这样做的好处就是更容易测试和维护正确的被封装的代码。你应该先将变量声明成private,然后有需要的话再扩大访问权限,如将private变成protected。Java中很多设计模式都使用了封装,工厂设计模式就是封装的一个例子,它封装了对象的创建,如果要引入新的“产品”,也不必更改现有的代码。
# 开放且封闭的设计理论(Open Closed Design Principle)
类、方法以及功能应该对扩展开放(新的功能),而对更改封闭。这是另一个优美的”SOLID”设计理论,这保证了有人更改已经经过测试了的代码。如果你要加入新的功能,你必须要先测试它,这正是开放且封闭的设计理论的目标。另外,Open Closed principle正是SOLID中的O的缩写。
# 单一责任原理(Single Responsibility Principle (SRP))
单一责任原理是另外一条”SOLID”设计理论,代表其中的“S”。每次一个类只有一个更改的原因,或者一个类只应该完成单一的功能。如果你将多过一个功能放在一个类中,它会将两个功能耦合在一起,如果你改变了其中的一个功能,可能会破坏另外一个功能,这样便需要更多的测试以确保上线时不出现什么岔子。
# 依赖注入或反转原理
容器会提供依赖注入,Spring非常好的实现了依赖注入。这条原理的美妙之处在于,每个被注入的类很容易的测试和维护,因为这些对象的创建代码都集中在容器中,有多种方法都可以进行依赖注射,譬如一些AOP框架如AspectJ使用的字节码注入(bytecode instrumentation),以及Spring中使用的代理器(proxy)。来看看这个依赖注射的例子吧。这一条正是SOLID中的”D”。
# 多用组合,少用继承
如果可能的话,多用组合,少用继承。可能有的人会不同意,但我确实发现组合的灵活性高过继承。组合可以在运行时通过设置某个属性以及通过接口来组合某个类,我们可以使用多态,这样就能随时改变类的行为,大大提高了灵活性。Effective Java也更倾向于使用组合。
# Liskov替代原理(Liskov Substitution Principle (LSP))
根据Liskov替代原理,子类必须可以替代父类,也就是使用父类的方法,也能够没有任何问题的和子类对象也兼容。LSP和单一责任原则以及接口分离原则的关系紧密。如果一个类比子类的功能要多,子类不能支持父类中的某些功能的话,就违反了LSP。为了遵循LSP原理,子类需要改进父类的功能,而不是减少功能。LSP代表SOLID中的”L”。
# 接口分离理论(Interface Segregation principle (ISP))
接口分离理论强调,如果客户端没有使用一个接口的话,就不要实现它。当一个接口包含两个以上的功能,如果客户端仅仅需要其中某个功能,而不需要另外一个,那么就不要实现它。接口的设计是件非常复杂的工作,因为一旦你发布了接口之后,就再也无法保证不破坏现有实现的情况下更改接口。分离接口的另一个好处就是,因为必须要实现方法才能使用接口,所以如果仅仅只有单一的功能,那么要实现的方法也会减少。
# 针对接口编程,而不是针对实现编程
尽量针对接口编程,这样如果要引入任何新的接口,也有足够的灵活性。在变量的类型、方法的返回类型以及参量类型中使用接口类型。很多程序员都建议这么做,包括Effective Java和head first design pattern等书。
# 代理理论(Delegation principle)
不要所有的事情都自己做,有时候要将任务代理给相应的类去做。运用代理模式最经典的例子就是equals()和hashCode()方法。为了比较两个对象的相等与否,我们没有用客户端代码去比较,而是让对象自己去比较。这么做的好处就是减少代码的重复,更容易更改行为。
所有的这些面相对象理论都能帮助你写出更灵活、高度一致且低耦合的代码。理论是第一步,更重要的是运用这些设计理论的能力。找出违反这些设计理论的地方,但是就像这个世界上没有什么是完美的一样,不要尝试着用设计模式和理论解决一切问题,因为它们往往是针对大型的企业级项目,有着更长的运行周期。换句话说小型的项目不一定值得这么做。
原文链接: Javarevisited 翻译: ImportNew.com - 唐小娟
译文链接: http://www.importnew.com/6445.html
- JVM
- 深入理解Java内存模型
- 深入理解Java内存模型(一)——基础
- 深入理解Java内存模型(二)——重排序
- 深入理解Java内存模型(三)——顺序一致性
- 深入理解Java内存模型(四)——volatile
- 深入理解Java内存模型(五)——锁
- 深入理解Java内存模型(六)——final
- 深入理解Java内存模型(七)——总结
- Java内存模型
- Java内存模型2
- 堆内内存还是堆外内存?
- JVM内存配置详解
- Java内存分配全面浅析
- 深入Java核心 Java内存分配原理精讲
- jvm常量池
- JVM调优总结
- JVM调优总结(一)-- 一些概念
- JVM调优总结(二)-一些概念
- VM调优总结(三)-基本垃圾回收算法
- JVM调优总结(四)-垃圾回收面临的问题
- JVM调优总结(五)-分代垃圾回收详述1
- JVM调优总结(六)-分代垃圾回收详述2
- JVM调优总结(七)-典型配置举例1
- JVM调优总结(八)-典型配置举例2
- JVM调优总结(九)-新一代的垃圾回收算法
- JVM调优总结(十)-调优方法
- 基础
- Java 征途:行者的地图
- Java程序员应该知道的10个面向对象理论
- Java泛型总结
- 序列化与反序列化
- 通过反编译深入理解Java String及intern
- android 加固防止反编译-重新打包
- volatile
- 正确使用 Volatile 变量
- 异常
- 深入理解java异常处理机制
- Java异常处理的10个最佳实践
- Java异常处理手册和最佳实践
- Java提高篇——对象克隆(复制)
- Java中如何克隆集合——ArrayList和HashSet深拷贝
- Java中hashCode的作用
- Java提高篇之hashCode
- 常见正则表达式
- 类
- 理解java类加载器以及ClassLoader类
- 深入探讨 Java 类加载器
- 类加载器的工作原理
- java反射
- 集合
- HashMap的工作原理
- ConcurrentHashMap之实现细节
- java.util.concurrent 之ConcurrentHashMap 源码分析
- HashMap的实现原理和底层数据结构
- 线程
- 关于Java并发编程的总结和思考
- 40个Java多线程问题总结
- Java中的多线程你只要看这一篇就够了
- Java多线程干货系列(1):Java多线程基础
- Java非阻塞算法简介
- Java并发的四种风味:Thread、Executor、ForkJoin和Actor
- Java中不同的并发实现的性能比较
- JAVA CAS原理深度分析
- 多个线程之间共享数据的方式
- Java并发编程
- Java并发编程(1):可重入内置锁
- Java并发编程(2):线程中断(含代码)
- Java并发编程(3):线程挂起、恢复与终止的正确方法(含代码)
- Java并发编程(4):守护线程与线程阻塞的四种情况
- Java并发编程(5):volatile变量修饰符—意料之外的问题(含代码)
- Java并发编程(6):Runnable和Thread实现多线程的区别(含代码)
- Java并发编程(7):使用synchronized获取互斥锁的几点说明
- Java并发编程(8):多线程环境中安全使用集合API(含代码)
- Java并发编程(9):死锁(含代码)
- Java并发编程(10):使用wait/notify/notifyAll实现线程间通信的几点重要说明
- java并发编程-II
- Java多线程基础:进程和线程之由来
- Java并发编程:如何创建线程?
- Java并发编程:Thread类的使用
- Java并发编程:synchronized
- Java并发编程:Lock
- Java并发编程:volatile关键字解析
- Java并发编程:深入剖析ThreadLocal
- Java并发编程:CountDownLatch、CyclicBarrier和Semaphore
- Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition
- Synchronized与Lock
- JVM底层又是如何实现synchronized的
- Java synchronized详解
- synchronized 与 Lock 的那点事
- 深入研究 Java Synchronize 和 Lock 的区别与用法
- JAVA编程中的锁机制详解
- Java中的锁
- TreadLocal
- 深入JDK源码之ThreadLocal类
- 聊一聊ThreadLocal
- ThreadLocal
- ThreadLocal的内存泄露
- 多线程设计模式
- Java多线程编程中Future模式的详解
- 原子操作(CAS)
- [译]Java中Wait、Sleep和Yield方法的区别
- 线程池
- 如何合理地估算线程池大小?
- JAVA线程池中队列与池大小的关系
- Java四种线程池的使用
- 深入理解Java之线程池
- java并发编程III
- Java 8并发工具包漫游指南
- 聊聊并发
- 聊聊并发(一)——深入分析Volatile的实现原理
- 聊聊并发(二)——Java SE1.6中的Synchronized
- 文件
- 网络
- index
- 内存文章索引
- 基础文章索引
- 线程文章索引
- 网络文章索引
- IOC
- 设计模式文章索引
- 面试
- Java常量池详解之一道比较蛋疼的面试题
- 近5年133个Java面试问题列表
- Java工程师成神之路
- Java字符串问题Top10
- 设计模式
- Java:单例模式的七种写法
- Java 利用枚举实现单例模式
- 常用jar
- HttpClient和HtmlUnit的比较总结
- IO
- NIO
- NIO入门
- 注解
- Java Annotation认知(包括框架图、详细介绍、示例说明)