面向对象
特性
封装:作用是信息保护,类通过暴露有限的接口,让外部通过函数来访问内部数据。
抽象:隐藏方法的具体实现,调用者只需关心方法提供了哪些功能,忽略如何实现。
继承:表示类之间is-a的关系,便于代码复用。
多态:子类可以替换父类/接口。提高代码的可扩展性、可复用性。
优点
- 把大规模的场景拆分为多个类,设计类之间的交互关系,应对复杂程序的开发。
- 基于四大特性,能写出易复用,易扩展,易维护的代码。
- 人性化,更贴近人的思考方式,容易理解。
常见误区
-
滥用getter、setter方法:违背了封装性,给用户带来过度的自由,可能会导致数据不一致。比如get到一个属性List infos,那用户就可以随意操作infos的元素了,此时并没有更新该类中和infos数据关联的其他属性。
-
滥用全局变量和全局方法:
问题一:
大而全的Consotant类(存全局常量)要避免,容易造成冲突影响代码可维护性,增加代码编译时间,也会让其他模块引入大量的无效常量影响复用性。
解决方案:分为多个类,AConstants,BConstants。问题二:
Utils类 ,大的Utils类(存全局方法)也有上面的问题。
抽象类和接口
抽象类是is-a的关系,为了解决代码复用问题。
接口是has-a的关系,表示具有某一组行为特征,解耦。 接口的本质是一组约定,是功能提供者给使用者的一个功能列表。
基于接口编程而非实现编程
- 接口中函数的命名不能包含任何细节,否则以后实现类出现替换类会很麻烦。
- 封装具体的细节。
- 为实现类定义抽象的接口。使用者依赖接口,不依赖接口实现。
多用组合少用继承
举个接+组合+委托的例子:
public interface Runable{
void run();
}
public class RunAbility implements Runable{
void run(){
//具体实现
}
}
public class Chicken implements Runable,Flyable{
//接口
private RunAbility runAbility= new RunAbility(); //组合
private FlyAbility flyAbility = new Flyability(); //组合
public void run(){
runAbility.run(); //委托
}
public void fly(){
flyability.fly();
}
}
继承有三种作用,表示类之间的is-a关系、解决代码复用的问题、支持多态的特性。这三个作用可以通过组合、接口、委托来达成。为了避免但继承层次过深,过复杂影响代码的课维护性,我们应该少用继承。
贫血模式的MVC架构 和 充血模型DDD对比
贫血模型中,VO、BO、Entity都属于纯粹的数据结构,业务逻辑主要在Service层中,这种模型将操作和数据分离,破坏了面向对象的封装特性,是一种典型的面向过程的风格。但对于业务不复杂的系统来说,这种模型简单而且够用。
充血模型要数据和对应的业务逻辑封装到同一个类中,属于面向对象的风格。DDD(Domain Driven Design)领域驱动设计。和贫血模型相比,该模型把业务逻辑放到Domain中,Service变得很薄,此时Service层负责的事情是:和Repository打交道、调用多个领域模型、和其他系统交互(记日志、发消息、事务、RPC等)
基于充血模型的DDD和贫血模型相比,Controller层和Repository层基本一样,差异主要是在Service层。
评判代码的几个维度
- 可维护性: 在不破坏原有设计,不引入bug的情况下,快速地修改或者添加代码。
- 可读性: 编码符合规范、命名合适、注释详尽、函数长短合适、模块划分清晰、高内聚低耦合
- 可扩展性:在不修改或者少修改代码的情况下,通过扩展添加新的代码。
- 简洁性:思从深而行从简。
- 可复用性:减少重复代码的编写。
- 可测试性:写的代码要容易写单元测试。