WEB开发模型-贫血模型和充血模型

本文探讨了软件架构中的贫血模型和充血模型。贫血模型将状态与行为分离,适用于清晰分层的系统;充血模型则融合状态与行为,更符合面向对象原则。文章通过实例比较了两者的优缺点,并提出在Web开发中推荐使用贫血模型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引入

在看《大网站技术架构》
这里写图片描述
其中第79页有一段说明:
这里写图片描述
那么今天来聊聊贫血和充血模型

一、贫血模型

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

二、充血模型

Model 中既包括状态,又包括行为,是最符合面向对象的设计方式。
以下为举例说明:
对于员工Employee来说,每个员工的属性有Id,Name,Sex,BirthDay,Parent(上级),行为有查找,保存,删除,职位调整(更换上级) 等
采用贫血模型实现

//Model:
public class Employee
    {
        public string Id { get; set; }
        public string Name { get; set; }
        public string Sex { get; set; }
        public DateTime? BirthDay { get; set; }
        /// <summary>
        /// 直属上级的Id
        /// </summary>
        public string ParentId { get; set; }
    }
//DB 层
//实现方法略    
public class EmpDAO
    {
        public static bool AddEmployee(Employee emp);
        public static bool UpdateEmployee(Employee emp);
        public static bool DeleteEmployee(Employee emp);
        public static Employee GetEmployeeById(string Id);
    }
//BLL 层
public class EmpBLL
    {
        public void Test()
        {
            Employee emp1 = new Employee() { Id = System.Guid.NewGuid().ToString(), Name = "张三", Sex = "男" };
            Employee emp2 = new Employee() { Id = System.Guid.NewGuid().ToString(), Name = "李四", Sex = "男", ParentId = emp1.Id };
           //插入员工
            EmpDAO.AddEmployee(emp1);
            EmpDAO.AddEmployee(emp2);

            //取员工的上级
            var emp2Parent = EmpDAO.GetEmployeeById(emp2.ParentId);
            var emp2Parent_Parent = EmpDAO.GetEmployeeById(emp2Parent.ParentId);

            //删除员工
            EmpDAO.DeleteEmployee(emp1);
            EmpDAO.DeleteEmployee(emp2);
        }
    }

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

//Model 层
public class Employee
    {
        public string Id { get; set; }
        public string Name { get; set; }
        public string Sex { get; set; }
        public DateTime? BirthDay { get; set; }
        /// <summary>
        /// 直属上级的Id
        /// </summary>
        public string ParentId { get; set; }
        private Employee _parent;

        public static Employee query(string id)
        {
            Employee emp = new Employee();
            //实现略,仅需填充emp的熟悉即可
            return emp;
        }
        /// <summary>
        /// 保存对象,实现略
        /// </summary>
        /// <returns></returns>
        public bool Save()
        {
            return true;
        }
        /// <summary>
        /// 删除对象,实现略
        /// </summary>
        /// <returns></returns>
        public bool Drop()
        {
            return true;
        }
        /// <summary>
        /// 上级领导,此处直接获得了Employee对象
        /// </summary>
        public Employee Parent
        {
            get
            {
                if (_parent != null)
                {
                    return _parent;
                }
                else
                {
                    _parent = query(this.ParentId);
                    return _parent;
                }
            }
            set
            {
                _parent = value;
                this.ParentId = _parent.Id;
                Save();
            }
        }
    }
//Service 层
public class EmpService
    {
        public void Test()
        {
            Employee emp1 = new Employee() { Id = System.Guid.NewGuid().ToString(), Name = "张三", Sex = "男" };
            Employee emp2 = new Employee() { Id = System.Guid.NewGuid().ToString(), Name = "李四", Sex = "男", ParentId = emp1.Id };
            //插入员工
            emp1.Save();
            emp2.Save();

            //取员工的上级
            var emp2Parent = emp2.Parent;
            var emp2Parent_Parent = emp2Parent.Parent;

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

总结:
  从两者Service层和BLL 层的代码区分来看,两者都是实现了业务功能和延迟加载。

贫血模型优点是系统的层次结构清楚,各层之间单向依赖。缺点是不够面向对象。

充血模型优点是面向对象,Business Logic符合单一职责,不像在贫血模型里面那样包含所有的业务逻辑太过沉重。缺点是比较复杂,对技术要求更高。

对于web开发,个人推荐用贫血模型。其实无论是采用哪种模型,都是可以的,只不过作为我们自己,要真正去理解为什么要这么做,以及怎样去解决问题,而不是学到一知半解,把两种方式混用,分出DAL 层来,却又采用充血模型去操作,然后又去遵循贫血模型的规范,把代码写的乱七八糟,层不是层(吐槽一下,在这样的项目里,让我很难受)。

好的代码,应该是简单的,应该是美的,应该是能解决问题而不是制造问题的,不要为了面向对象而面向对象。

以上都是我的个人理解,有不对的地方,欢迎大家指正。

ps:最近在做项目,发现有人在贫血模型中使用Parent类似的这种类,但是又不能解决延时加载的问题,或者是每次用的时候都要再加载,没有添加Parent的意义,反而导致这些对象不能及时回收,心有所感,所以在这里总结一下,与大家分享。

扩展阅读

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值