領域驅動模型
要想了解領域驅動模型,首先你要先知道基於領域驅動的架構目錄,如下圖
-
Repository 數據倉庫,用於數據訪問和持久化(功能是基於業務來做,並在業務里定義接口來約束數據庫的操作功能)
-
Model 業務處理
-
建模(模型封裝業務需要的數據)
-
接口(約束數據庫的訪問功能)
-
協調 領域模型 和 數據訪問處理業務(調用數據庫訪問的xx方法,並把處理的數據封裝到模型中),把模型返回給服務層
-
service 服務層(請求有規則,響應有規則)---調用業務處理的協調者的協調方法
-
UI層 負責請求對應的類
領域驅動設計,用自己的話說就是業務邏輯場景驅動整個程序代碼的設計
還是不懂?那看個例子吧,這個例子再尋常不過了
登陸場景
場景分析:
- 常見的兩種登陸方法--用戶名+密碼 或 郵箱+密碼,這就是前端提交后台要處理的數據,三個一起交過去,沒有的就等於None
- 登陸失敗,要顯示錯誤信息,登陸成功,就要顯示個人信息,所以后台處理完后要返回這些數據
領域模型,當然是從模型入手了,模型怎么建了,模型是要封裝所有需要的數據,那我們需要哪些數據---登陸狀態,錯誤信息,以及個人信息,其中涉及數據庫訪問的就是個人信息了,那么模型就要封裝個人信息
- 模型---個人信息:id,用戶名,郵箱,最近登陸時間,用戶類型,會員類型(其中用戶類型和會員類型又可以分出小模型)
所以在Model里建一個User.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
#建立模型
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
|
除了建模型,還在這里定義接口(接口主要限制數據庫的訪問功能),分析認證的過程是郵箱或用戶名,可以分開定義成兩個方法,一個用用戶名驗證的方法,一個就是用郵箱驗證的方法,最后還要有更新用戶登陸時間的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
#定義接口
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,專門用連接數據庫的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
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文件接口的方法,並處理得到的數據封裝到模型里
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
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對象,這里可以用依賴注入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#協調者,進行認證
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
1
2
3
4
5
6
7
8
9
10
|
'''
對於request類的建立規則就是,前端發來多少項數據就對應建立幾個字段
'''
class
UserRequest:
def
__init__(
self
,usr,pwd,ema):
self
.username
=
usr
self
.password
=
pwd
self
.email
=
ema
|
然后我們定義一下響應規則,在這里我們必須清楚,返回給客戶看的是字符串,業務層返回模型里的字段帶有對象的就到這里細化
Response.py
1
2
3
4
5
6
7
8
9
10
11
|
'''
需要返回的信息無非就是執行狀態,錯誤信息,以及用戶信息
其中用戶信息又封裝到ModelView對象里
'''
class
UserResponse:
def
__init__(
self
,status
=
True
,message
=
'',model_view
=
None
):
self
.status
=
status
self
.message
=
message
self
.modelView
=
model_view
|
ModelView.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
'''
在服務層,模型數據的接收者,並且細化,在這里是封裝客戶信息
'''
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對象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
'''
在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層導入上述代碼類,並實例對象,調用服務層驗證方法就可以了
我們看到,整個代碼設計都是由登陸這個業務邏輯驅動的
不過你感覺這繞來繞去的,感覺沒什么好的,可以這么說小型項目,毫無疑問增加很多不必要的代碼,但是對於大型網站,協作與維護是非常方便的,只能因景而異啦
再加個圖吧