领域驱动模型

  要想了解领域驱动模型,首先你要先知道基于领域驱动的架构目录,如下图

  • Repository  数据仓库,用于数据访问和持久化(功能是基于业务来做,并在业务里定义接口来约束数据库的操作功能)

  • Model  业务处理

  1. 建模(模型封装业务需要的数据)

  2. 接口(约束数据库的访问功能)

  3. 协调 领域模型  和  数据访问处理业务(调用数据库访问的xx方法,并把处理的数据封装到模型中),把模型返回给服务层

  • service 服务层(请求有规则,响应有规则)---调用业务处理的协调者的协调方法

  • UI层  负责请求对应的类

  领域驱动设计,用自己的话说就是业务逻辑场景驱动整个程序代码的设计

  还是不懂?那看个例子吧,这个例子再寻常不过了

  登陆场景

场景分析:

  • 常见的两种登陆方法--用户名+密码  或  邮箱+密码,这就是前端提交后台要处理的数据,三个一起交过去,没有的就等于None
  • 登陆失败,要显示错误信息,登陆成功,就要显示个人信息,所以后台处理完后要返回这些数据

  领域模型,当然是从模型入手了,模型怎么建了,模型是要封装所有需要的数据,那我们需要哪些数据---登陆状态,错误信息,以及个人信息,其中涉及数据库访问的就是个人信息了,那么模型就要封装个人信息

  • 模型---个人信息:id,用户名,邮箱,最近登陆时间,用户类型,会员类型(其中用户类型和会员类型又可以分出小模型)

所以在Model里建一个User.py

#建立模型

class VipType:

    dic = {
        1:'金牌',
        2:'银牌',
        3:'铜牌'
    }

    def __init__(self,nid):
        self.nid = nid

    @property
    def caption(self):
        for i in VipType.dic:
            if i == self.nid:
                return VipType.dic[i]


class UserType:

    dic = {
        1:'普通用户',
        2:'商户',
        3:'管理员'
    }

    def __init__(self,nid):
        self.nid = nid

    @property
    def caption(self):
        for j in UserType.dic:
            if self.nid == j:
                return UserType.dic[j]

class User:

    def __init__(self,nid,username,email,last_login,vip_type_obj,user_type_obj):
        self.nid = self.nid
        self.username = username
        self.email = email
        self.last_login = last_login
        self.vip_type = vip_type_obj
        self.user_type = user_type_obj

   除了建模型,还在这里定义接口(接口主要限制数据库的访问功能),分析认证的过程是邮箱或用户名,可以分开定义成两个方法,一个用用户名验证的方法,一个就是用邮箱验证的方法,最后还要有更新用户登陆时间的方法

#定义接口

class IUserRepository:

    def fetch_one_by_username(self,username,password):
        '''
        通过密码到数据库进行验证
        :param username: 用户名
        :param password: 密码
        :return:
        '''

    def fetch_one_by_email(self,email,password):
        '''
        通过邮箱到数据库进行验证
        :param email:
        :param password:
        :return:
        '''

    def update_last_login_by_nid(self,nid,cur_date):
        '''
        通过nid更新数据库的登陆时间
        :param nid: id
        :param cur_date: 最新时间
        :return:
        '''

   好!接口和模型定义好后,就可以去Repository把接口里方法实现了

  • 数据访问,数据访问,肯定要要连接上数据库才能访问

  在Repository创建了一个DbConnection.py,专门用连接数据库的

import pymysql
import Config


class DbConnection:

    def __init__(self):
        #数据库的信息写在配置文件里
        self.__conn_dict = Config.PY_MYSQL_CONN_DICT
        self.conn = None
        self.cursor = None

    #连接数据库,创建游标
    def connect(self,cursor=pymysql.cursors.DictCursor):
        self.conn = pymysql.connect(**self.__conn_dict)
        self.cursor = self.conn.cursor(cursor=cursor)
        return self.cursor

    #关闭游标以及数据库
    def close(self):
        self.conn.commit()
        self.cursor.close()
        self.conn.close()

   做好了这一步,访问数据库时只要实例化这样一个对象就可以了

  针对业务层User建立一个UserRepository.py专门实现User文件接口的方法,并处理得到的数据封装到模型里

from Model.User import VipType,User,UserType,IUserRepository
#进行数据库连接的另成立模块
from .DbConnection import DbConnection


class UserDb(IUserRepository):

    def __init__(self):
        self.conn = DbConnection()

    def fetch_one_by_email(self,email,password):
        ret = None
        cursor = self.conn.connect()
        sql = '''select nid,username,email,last_login,vip_type,user_type
         from UserInfo where email=% and password=%'''
        cursor.execute(sql,(email,password))
        #db_result是一个字典
        db_result = cursor.fetchone()
        self.conn.close()
        if db_result:
            #调用模型进行封装
            ret = User(nid=db_result['nid'],
                       username=db_result['username'],
                       email=db_result['email'],
                       last_login=db_result['last_login'],
                       user_type=UserType(nid=db_result['user_type']),
                       vip_type=VipType(nid=db_result['vip_type']))
            return ret



    def fetch_one_by_username(self,username,password):
        ret = None
        cursor = self.conn.connect()
        sql = '''select nid,username,email,last_login,vip_type,user_type
         from UserInfo where username=% and password=%'''
        cursor.execute(sql,(username,password))
        #db_result是一个字典
        db_result = cursor.fetchone()
        self.conn.close()
        if db_result:
            #调用模型进行封装
            ret = User(nid=db_result['nid'],
                       username=db_result['username'],
                       email=db_result['email'],
                       last_login=db_result['last_login'],
                       user_type=UserType(nid=db_result['user_type']),
                       vip_type=VipType(nid=db_result['vip_type']))
            return ret

    def update_last_login_by_nid(self,nid,cur_date):
        cursor = self.conn.connect()
        sql = '''update UserInfo set last_login=%s where nid=%s'''
        cursor.execute(sql,(cur_date,nid))
        self.conn.close()

   定义好接口方法后我们需要再次来到业务层,在Model的User.py写入协调类,用于调用数据仓库的方法,并把封装好的模型对象返回给服务层,在调用方法前,需要需要先实例UserRepository对象,这里可以用依赖注入

#协调者,进行认证

class UserService:

    def __init__(self,user_repostiory):
        self.db = user_repostiory

    def check_login(self,user,pwd,ema):
        if user:
            user_model = self.db.fetch_one_by_username(username=user,password=pwd)
        else:
            user_model = self.db.fetch_one_by_email(email=ema,password=pwd)
        if user_model:
            current_date = datetime.datetime.now()
            self.db.update_last_login_by_nid(user_model.nid,current_date)
        return user_model

  那么对于协调者来说,验证的数据哪里来,没错就是服务层,不仅接收处理数据还是传递客户输入的数据进行验证,并且在服务层里协调类里调用业务层的协调方法

   在开始写服务层时,你必须理解这句话,就是请求有规则,响应有规则---请求就是传客户数据,响应就是收业务处理数据,到了服务层就要按服务层的规则,按照服务层定义进行封装数据

  在服务层下建个User的文件夹专门服务业务层的User

  我们先定义‘请求规则’--Request.py

'''
对于request类的建立规则就是,前端发来多少项数据就对应建立几个字段
'''

class UserRequest:

    def __init__(self,usr,pwd,ema):
        self.username = usr
        self.password = pwd
        self.email = ema

   然后我们定义一下响应规则,在这里我们必须清楚,返回给客户看的是字符串,业务层返回模型里的字段带有对象的就到这里细化

Response.py

'''
需要返回的信息无非就是执行状态,错误信息,以及用户信息
其中用户信息又封装到ModelView对象里
'''

class UserResponse:

    def __init__(self,status=True,message='',model_view=None):
        self.status = status
        self.message = message
        self.modelView = model_view

 ModelView.py

'''
在服务层,模型数据的接收者,并且细化,在这里是封装客户信息
'''
class UserModelView:

    def __init__(self,nid,username,email,
                 last_login,user_type_id,user_type_caption,
                 vip_type_id,vip_type_caption):
        self.nid = nid
        self.username = username
        self.email = email
        self.last_login = last_login
        self.user_type = user_type_id
        self.user_type_caption = user_type_caption
        self.vip_type = vip_type_id
        self.vip_type_caption = vip_type_caption

   最后剩下就是调用业务层协调者和把数据返回给UI层的服务层协调者了,这里要调用业务层的协调者就必须实例一个业务层的UserService对象,这个通过参数的形式传入到服务层协调类的构造方法里,就又要用到依赖注入了,并且最终的信息要封装到服务层的规则里(Response),所以在定义验证方法里实例Response对象

'''
在Service里,接收request对象里封装信息
调用model业务层的方法做验证,先要实例业务层service对象(写在构造方法里)
把验证的结果信息封装到response对象里
'''

from Services.User.Response import UserResponse
from Services.User.ModelView import UserModelView

class service:

    def __init__(self,model_user_service):
        self.modelUserService = model_user_service  #业务层协调者

    def check_login(self,user_request):
        response = UserResponse()

        try:
            model = self.modelUserService.check_login(user=user_request.usr,pwd=user_request.pwd,ema=user_request.ema)
            if model:
               UserModelView(nid=model.nid,
                             username=model.username,
                             email=model.email,
                             last_login=model.last_login,
                             user_type_id=model.user_type.nid,
                             user_type_caption=model.user_type.caption,
                             vip_type_id=model.vip_type.nid,
                             vip_type_caption=model.vip_type.caption)
               response.modelView = UserModelView
            else:
                raise Exception('密码错误!')

        except Exception as e:
            response.status = False
            response.message = str(e)

        return response

   最后在UI层导入上述代码类,并实例对象,调用服务层验证方法就可以了

  我们看到,整个代码设计都是由登陆这个业务逻辑驱动的

  不过你感觉这绕来绕去的,感觉没什么好的,可以这么说小型项目,毫无疑问增加很多不必要的代码,但是对于大型网站,协作与维护是非常方便的,只能因景而异啦

  再加个图吧

原文地址:https://www.cnblogs.com/xinsiwei18/p/5938225.html