领域驱动模型
要想了解领域驱动模型,首先你要先知道基于领域驱动的架构目录,如下图
-
Repository 数据仓库,用于数据访问和持久化(功能是基于业务来做,并在业务里定义接口来约束数据库的操作功能)
-
Model 业务处理
-
建模(模型封装业务需要的数据)
-
接口(约束数据库的访问功能)
-
协调 领域模型 和 数据访问处理业务(调用数据库访问的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层导入上述代码类,并实例对象,调用服务层验证方法就可以了
我们看到,整个代码设计都是由登陆这个业务逻辑驱动的
不过你感觉这绕来绕去的,感觉没什么好的,可以这么说小型项目,毫无疑问增加很多不必要的代码,但是对于大型网站,协作与维护是非常方便的,只能因景而异啦
再加个图吧