WEB 开发中的『贫血模型』和『充血模型』

贫血模型

所谓贫血模型,是指Model 中,仅包含状态(属性),不包含行为(方法),采用这种设计时,需要分离出DB层,专门用于数据库操作(数据库作为状态)。

简单例子

对于员工Employee来说,每个员工的属性有Id,Name,Sex,BirthDay,Parent(上级),行为有查找,保存,删除,职位调整(更换上级) 等
采用贫血模型实现

// Model层
package entity

import (
    "time"
)

type Employee struct {
    Id       uint      `json:"id"`
    Name     string    `json:"name"`
    Sex      string    `json:"sex"`
    Birthday time.Time `json:"birthday"`
    ParentId uint      `json:"parent_id"`
}

// dao层
package dao

import (
    "trash/entity"
)

type EmpDAO struct {
}

// 添加员工,实现方法略
func (p *EmpDAO) AddEmployee(emp *entity.Employee) int64 {
    return 1
}

// 更新员工,实现方法略
func (p *EmpDAO) UpdateEmployee(emp *entity.Employee) int64 {
    return 1
}

// 删除员工,实现方法略
func (p *EmpDAO) DeleteEmployee(emp *entity.Employee) int64 {
    return 1
}

// 获取员工,实现方法略
func (p *EmpDAO) GetEmployeeById(id uint) entity.Employee {
    var emp entity.Employee
    emp.Id = uint(1)
    emp.Name = "张三"
    return emp
}

// service层
package service

import (
    "fmt"
    "time"
    "trash/dao"
    "trash/entity"
)

type EmpService struct {
}

var empdao = new(dao.EmpDAO)

func (p *EmpService) Test() {

    //转化所需模板
    timeLayout := "2020-01-02"
    //重要:获取时区
    loc, _ := time.LoadLocation("Local")
    //使用模板在对应时区转化为time.time类型

    var emp1 = new(entity.Employee)

    emp1.Id = uint(1)
    emp1.Name = "张三"
    emp1.Sex = "男"
    birthday1, _ := time.ParseInLocation(timeLayout, "1990-08-25", loc)
    emp1.Birthday = birthday1

    var emp2 = new(entity.Employee)
    emp2.Id = uint(2)
    emp2.Name = "李四"
    emp2.Sex = "男"
    emp2.ParentId = emp1.Id
    birthday2, _ := time.ParseInLocation(timeLayout, "1995-01-25", loc)
    emp2.Birthday = birthday2

    empdao.AddEmployee(emp1)
    empdao.AddEmployee(emp2)

    // 获取员工上级
    var emp2Parent = empdao.GetEmployeeById(emp2.ParentId)
    fmt.Print(emp2Parent)

    // 删除员工信息
    empdao.DeleteEmployee(emp1)
}

充血模型

Model 中既包括状态,又包括行为,是最符合面向对象的设计方式。

简单例子

若采用充血模型设计,则应只分两层 ,Model 层(包含状态和行为)和Service(BLL) 层

// Model 层
package entity

import (
    "time"
)

type Employee struct {
    Id       uint      `json:"id"`
    Name     string    `json:"name"`
    Sex      string    `json:"sex"`
    Birthday time.Time `json:"birthday"`
    ParentId uint      `json:"parent_id"`
    Parent   *Employee
}

// 保存员工,实现方法略
func (p *Employee) Save() int64 {
    return 1
}

// 删除员工,实现方法略
func (p *Employee) Drop() int64 {
    return 1
}

// 获取员工,实现方法略
func (p *Employee) Query(id uint) Employee {
    var emp Employee
    emp.Id = id
    return emp
}

func (p *Employee) GetParent() *Employee {
    if p.Parent != nil {
        return p.Parent
    } else {
        var p = new(Employee)
        p.Id = uint(1)
        p.Name = "张三"
        p.Sex = "男"
        return p
    }

}

// Service(BLL)层
package service

import (
    "fmt"
    "time"
    "trash/entity"
)

type EmpService struct {
}

func (p *EmpService) Test() {

    //转化所需模板
    timeLayout := "2020-01-02"
    //重要:获取时区
    loc, _ := time.LoadLocation("Local")
    //使用模板在对应时区转化为time.time类型

    var emp1 = new(entity.Employee)

    emp1.Id = uint(1)
    emp1.Name = "张三"
    emp1.Sex = "男"
    birthday1, _ := time.ParseInLocation(timeLayout, "1990-08-25", loc)
    emp1.Birthday = birthday1

    var emp2 = new(entity.Employee)
    emp2.Id = uint(2)
    emp2.Name = "李四"
    emp2.Sex = "男"
    emp2.ParentId = emp1.Id
    birthday2, _ := time.ParseInLocation(timeLayout, "1995-01-25", loc)
    emp2.Birthday = birthday2

    emp1.Save()
    emp2.Save()

    // 获取员工上级
    var emp2Parent = emp2.GetParent()
    fmt.Print(emp2Parent)

    // 删除员工信息
    emp1.Drop()
    emp2.Drop()
}

总结

从两者Service层和BLL 层的代码区分来看,两者都是实现了业务功能和延迟加载。
贫血模型优点是系统的层次结构清楚,各层之间单向依赖。缺点是不够面向对象。充血模型优点是面向对象,Business Logic符合单一职责,不像在贫血模型里面那样包含所有的业务逻辑太过沉重。缺点是比较复杂,对技术要求更高。

以上都是我阅读他人文章做的笔记,有遗漏或者不对的地方,欢迎大家指正。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容