PHP业务逻辑层和数据访问层设计
1、面向对象能给我们什么?
进行分析之前,我们先来复习一下面向对象。
对象是要进行研究的任何事物。
类是具有相同或相似性质的对象的抽象。
面向对象的要素:封装、继承、多态。
面向对象目的是:如何分配职责。
面向对象设计原则:
- 单一职责原则 (SRP) 一个类,只有一个引起它变化的原因。
- 开放-封闭原则 (OCP)(对外)可扩展,(对内)不可修改。
- 李氏替换原则 (LSP) 子类型必须能够完全替换其父类型。
- 依赖倒置原则 (DIP) 要依赖于抽象,不要依赖于具体。
- 接口隔离原则 (ISP) 使用多个专门的接口比使用单一的总接口好;
- 合成/聚合复用原则 (Composite/Aggregate Reuse Principle,CARP)在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新的对象通过向这些对的委派达到复用已有功能的目的。
- 最小知识原则(Principle of Least Knowledge,PLK,也叫迪米特法则)不要和陌生人说话。
2、业务逻辑层
在web应用中,我们通常使用MVC分层架构模式来将职责分离。
MVC模式的目的是实现一种动态的程序设计,使后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能。除此之外,此模式通过对复杂度的简化,使程序结构更加直观。软件系统通过对自身基本部份分离的同时也赋予了各个基本部分应有的功能。
- 控制器(Controller)- 负责转发请求,对请求进行处理。
- 视图(View) – 界面设计人员进行图形界面设计。
- 模型(Model) – 用于封装与应用程序的业务逻辑相关的数据(属性)以及对数据的处理方法(行为)。
按照这样的定义,模型是传说中的领域模型的实现类,实现业务逻辑,但数据访问层是不属于模型的。
我们MVC中的模型可以定义为领域逻辑。
领域逻辑有多中架构模式,如:
事务脚本: 使用过程来设计业务逻辑,每个过程处理来自表现层的单个请求。
领域模型: 合并了行为和数据(属性)的领域对象模型。
表模块: 处理某一数据库表或视图中所有行的业务逻辑的一个实例。
服务层: 通过一个服务来定义应用程序边界,在服务层中建立一组可用的操作集合,并在每个操作内部协调应用程序的响应。
表模块模型是把领域模型和数据访问合并起来了。
事务脚本是面向过程的,不利于分配职责。
服务层是在领域模型上一层,引入服务层的话系统就复杂很多了。
如果项目相对较小,业务逻辑很简单,也是用一种固定的数据库(如MySQL),就不需要分业务逻辑层和数据访问层,可以选择表模块模式组织领域逻辑。
如果项目的功能会随着时间越来越多,需求不好控制,我们需要更多的考虑到减少依赖和明确职责,这样我们使用领域模型的领域逻辑架构模式来作为MVC中的M层,对对象的属性和行为进行描述,另外添加一个数据访问层给业务逻辑提供数据。
3、数据访问层
在martin fowler的《企业应用架构模式》介绍了4种数据源架构模式:表数据入口、行数据入口、活动记录、数据映射器。此外还有ResultSet、 Metadata等模式。
(1)表数据入口(Table Data Gateway):充当数据库表访问入口的对象。一个实例处理表中所有的行。
(2)行数据入口(Row Data Gateway):充当数据源中单条记录入口的对象。每行一个实例。
(3)活动记录(Active Record):一个对象,它包装数据库表或视图中某一行,封装数据库访问,并在这些 数据上增加了领域逻辑。
(4)数据映射器(Data Mapper):在保持对象和数据库彼此独立的情况下在二者之间移动数据的一个映射器层。它能够在内存对象和数据库中传递数据并保持他们彼此独立,以分离领域与数据源。
活动记录集可以使用在不分业务逻辑层和数据访问层的情况。
最理想的情况下是使用数据映射器模式,使用ORM层,业务逻辑层只出力领域中的行为,增加VO模型对对象的属性进行描述和validate,通过DAO访问数据库。这样就能彻底的面向对象了,在业务逻辑、数据访问、视图中都直接操作直观的VO模型类。但是回到现实中,我们发现这样做起来把事情复杂化了。
我们PHP程序员对SQL语句就像是C/C++程序员离不开指针一样,使用sql语句非常灵活,更利于性能优化。绝大多数情况下,我们的系统用什么数据库都是预先定好了的,转移的可能性非常少。而且我们用面向对象分析的时候,只分析到业务逻辑层(领域模型)。我们只用kv数组/对象替代VO对象在PHP中不论是数据存贮还是数据分析和处理,都更灵活。因此,由语言本身决定,表数据入扣模式更适合做PHP的数据访问层。
综上,我们MVC中的模型是对领域对象模型的实现,对业务对象的属性和行为负责,组成业务逻辑层,通过表数据入口模式对业务逻辑层进行支持。