OOP
继承与组合
关系浅时可用继承,复杂时组合代替,像装饰者模式、策略模式、组合、模板等设计模式
当没办法修改一个外部类代码时,可以通过继承形式进行重写函数代码
class ForeignApi{
public void hello(){ // need override}
}
class NewApi extends ForeignApi{
@Override
public void hello() { //new thing}
}
class God{
public void xxxFunction(ForeignApi api){
// need override
api.hello();
}
void main(){
ForeignApi api=new NewApi()
xxxFunction(api);
}
}
为什么不推荐用继承
继承层次过深,继承关系过于复杂影响可读性和可维护性
比如说粽子有甜的、咸的、辣的,AbstractSweet··· 同时还有方的三角形的,AbstractSweetTriangle··· 太过复杂
如果用接口实现
- 道滘粽子 implements Sweetable,Triangle
- 福建粽子 implements Slaty, Triangle
- 但每个粽子都要实现重复的三角形代码,造成代码重复
如果用组合实现
给接口定义实现类, TriangleAblity{ triangle(){ //make triangle}
原本的实现地方通过委托,把实现代码交给 Ablity
class 道滘粽子 implements Triangle{ // 组合 TriangleAblity ablity=new TriangleAblity(); @Override public void triangle(){ // 委托 ablity.triangle() } }
抽象类与接口
抽象类不能被实例化,只能被子类继承,表达 is-a 的关系
- 实现代码复用功能
- 编译器强制要求实现 Override 抽象方法
而接口表达 has-a 关系,表示具有某种功能,表达协议(contract)
侧重于解耦,对行为的一种抽象,表达一组协议或者契约(比如说 Cloneable)
如何实现基于接口编程呢?(三点)
- 函数命名不暴露细节(比如说 sendRabbitMq)
- 封装具体的实现细节,对外提供服务的接口应该是抽象涵盖所有含义的,比如说+send(msg)/+receive()
- 为实现类定义抽象的接口。使用者依赖接口实现 RabbitMq implements Mq
四大特性
封装(Encapsulation)
- 通过暴露有限的访问接口,授权外部通过类的方式访问内部数据或者数据(通过修饰符 private、protected、public 控制)
- 保护数据不被随意修改、提高可维护性
- 提高类的易用性
抽象
- 关心方法提供什么功能,不关注实现方式(通过 interface、abstract class 实现)
- 提高代码可扩展性、维护性,修改实现不需要改变定义,减少改动范围
- 解决复杂系统,有效过滤不必要的关注信息
继承
- 表达类之间 is-a 的关系,比如 Dog is a Animal,分为单继承、多继承
- 解决代码复用的问题
多态
- 指子类可以替代父类
- 继承、接口、duck-typing
- 提高代码的扩展性和复用性
面向对象与面向过程的开发模式
贫血与充血
贫血(Anemic Domain Model)
- 数据与操作分离,PrizePO、PrizeBO+搭配 PrizeRepository 进行操作
充血(Rich Domain Model) 与 DDD(Domain Driven Design)
将原本操作数据的逻辑迁移至实体类中,由 Service 操作数据变成委托实体自己操作数据
public class Prize{ private long remainStock; public void deductPrizeInventory(){ this.remainStock--; } } class XXXService{ public void deductPrizeStock(){ Prize prize= xxx.getPrize(); // 委托Prize进行奖品库存的扣减 prize.deductPrizeInventory(); } }
DDD 与 MVC 的差异
DDD 的特点
DDD 开发时要划分业务领域间的边界,定义上下文,跨领域访问都必须通过制定服务操作
MVC 的特点
MVC 大多是 SQL 驱动的开发模式,由表结构定义到具体的仓储层、服务处、操作器层(Repository/Service/controller)换句话说对应 PO、Entity、VO
差异
主要在 Service 层的实现,Controller 和 Repository 层基本一致
DDD 的 Service 相比更薄
- 负责与仓储层交流
- 负责跨领域的访问以及聚合的功能,比如说想要调用第三方系统进行奖品的发放,就要通过 Service 去访问第三方系统的逻辑。如果简单可以集成到 Service,如果较为复杂,可以将发奖模块抽象成一个领域模型
Controller 与 Repository 都是贫血模型
- Controller 一般只负责将数据透传给其他系统,不涉及复杂的业务逻辑,使用 VO 简单开发即可
- Repository 一般只负责与第三方系统进行交互,通常只是数据的 CRUD,不涉及复杂的业务逻辑,简单开发即可