我,前端,不想卷技術(shù)了……卷下整潔架構(gòu)
# 關(guān)注并星標(biāo)騰訊云開(kāi)發(fā)者
# 每周3 | 談?wù)勎以隍v訊的架構(gòu)設(shè)計(jì)經(jīng)驗(yàn)


對(duì)于每個(gè)軟件系統(tǒng),我們都可以通過(guò)行為和架構(gòu)兩個(gè)維度來(lái)體現(xiàn)它的實(shí)際價(jià)值。


3.2 整潔架構(gòu)和其他架構(gòu)對(duì)比
3.2.1 六邊形架構(gòu)
3.2.2 DDD 分層架構(gòu)
3.2.3 對(duì)比分析

4.1 戰(zhàn)略階段:分析業(yè)務(wù),建立領(lǐng)域模型
4.1.1 分析業(yè)務(wù)流程
-
識(shí)別業(yè)務(wù)參與者
-
分析參與者在不同階段發(fā)生的動(dòng)作及觸發(fā)的狀態(tài)
-
使用雙軸泳道圖描述業(yè)務(wù)流程
4.1.2 提取領(lǐng)域?qū)ο?/span>
-
實(shí)體
-
值對(duì)象
-
聚合根
4.1.3 劃分界限,識(shí)別模塊
4.2 戰(zhàn)術(shù)階段:工程落地,搭建分層架構(gòu)
4.2.1 分層實(shí)現(xiàn)
-
使用充血模型來(lái)描述實(shí)體
-
結(jié)合具體場(chǎng)景,允許部分依賴(lài)實(shí)現(xiàn)
// 用戶實(shí)體 ./shared/domain/entities/user.ts
import cookie from 'cookie';
export interface IUserService { getCity(id: string): Promise<City>;}
export class User { // 用戶Id public id: string; // 用戶服務(wù) private userService: IUserService; constructor(id: string, name: string, userService: IUserService) {} // 檢查用戶是否登錄 public isLogin(): boolean { if (cookie.get('openid') && cookie.get('access_token')) { return true; } return false; } // 登錄 public login(): Promise<void> { if (!this.isLogin()) { goToURL('https://www.xxx.com/login'); } } // 退出登錄 public logout(): Promise<void> { cookie.remove('openid'); cookie.remove('access_token'); goToURL('https://www.xxx.com/login'); } // 獲取用戶所在城市 public getCity(): Promise<City> { return this.userService.getCity(this.id); }}
// 商品實(shí)體 ./shared/domain/entities/product.ts
export interface IProductService { getBaseInfoById(id: string): Promise<ProductBaseInfo>; getStockInfoByIdAndCity(id: string, city: City): Promise<ProductStockInfo>;}
export class Product { // 商品Id public id: string; // 用戶服務(wù) private productService: ProductService; constructor(id: string, name: string; productService: IProductService) {} // 獲取商品詳情 public async getDetail() { // 獲取商品基本信息和庫(kù)存信息 const baseInfo = await this.productService.getBaseInfoById(this.id); const stockInfo = await this.productService.getStockInfoById(this.id, city); // 組合詳情數(shù)據(jù) const detail = { id: this.id, name: baseinfo.name, images: baseinfo.name, stockNum: stockInfo.num, }; return detail; }
// 根據(jù)地區(qū)獲取庫(kù)存信息 public addToCart(num:number) { return this.productService.getStockInfoById(this.id, city); }};
// 獲取商品詳情用例 ./shared/domain/usercases/get-product-detail.ts
import { User } from './shared/domain/entities/user.ts';import { Product } from './shared/domain/entities/product.ts';// 用戶服務(wù)、產(chǎn)品服務(wù)的具體實(shí)現(xiàn),見(jiàn)適配器層import { UserService } from './server/services/user-service.ts';import { ProductService } from './server/services/product-service.ts';
export async function getProductDetail(userId: string, productId: string) { // 示例化用戶實(shí)體和商品實(shí)體,省略部分代碼 const user = new User(userId, UserService); const product = new Product(productId, ProductService); // 獲取用戶所在城市 const city: City = await user.getCity(); // 獲取商品基本信息 const productBaseInfo = await product.getBaseInfo(); // 根據(jù)城市獲取商品庫(kù)存 const productStockInfo = await product.getStockInfo(city); return { baseInfo: productBaseInfo, stockInfo: productStockInfo, };}
// 用戶服務(wù)具體實(shí)現(xiàn) ./server/services/user-service.tsimport { IUserService } from './shared/domain/entities/user.ts';
class UserService implements IUserService { getCity(userId: string): Promise<City> { // 通過(guò)后臺(tái)接口獲取用戶所在城市 const resp = get('https://api.xxx.com/queryUserCity', { userId }); if (resp.ret !== 0) { throw new Error('查詢用戶所在城市失敗'); } return resp.data.city as City; } }
// 商品服務(wù)具體實(shí)現(xiàn) ./server/services/product-service.tsimport { IProductService } from './shared/domain/entities/product.ts';
class ProductService implements IProductService { getBaseInfoById(id: string): Promise<ProductBaseInfo> { // 調(diào)用后臺(tái)商品服務(wù)接口,省略具體實(shí)現(xiàn) } getStockInfoByIdAndCity(id: string, city: City): Promise<ProductStockInfo> { // 調(diào)用后臺(tái)商品服務(wù)接口,省略具體實(shí)現(xiàn) }}
// 商品詳情頁(yè) store ./client/store/product-store.tsimport { getProductDetial } from './shared/domain/usercases/get-product-detail.ts'
export default new Vuex.Store({ state: { productDetail: ProductDetail, }, mutations: { async getProductDetail(state) { // 用例已包含具體業(yè)務(wù)邏輯,這里直接調(diào)用用例方法 state.productDetail = getProductDetial(userId, productId); }, },}
// 商品詳情頁(yè) ./client/pages/product-detail.ts
import { defineComponent, ref, onMounted } from 'vue';
export defineComponent({ name: 'ProudctDetailPage', setup() { onMounted(() => { setLoading(true); await store.getProductDetail(); setLoading(false); });
return () => ( <div> <p> {{ store.productDetail.baseInfo }}</p> <p> {{ store.productDetail.stockInfo }}</p> </div> ); },});
import vue from 'Vue'
vue.render(App);
4.3.3 架構(gòu)及目錄示例

??前端業(yè)務(wù)越來(lái)越復(fù)雜,你還有哪些降低業(yè)務(wù)復(fù)雜度的開(kāi)發(fā)方法??歡迎留言。我們將挑選一則最有意義的評(píng)論,為其留言者送出騰訊定制-手機(jī)支架1個(gè)(見(jiàn)下圖)。10月18日中午12點(diǎn)開(kāi)獎(jiǎng)。

????歡迎加入騰訊云開(kāi)發(fā)者社群,社群專(zhuān)享券、大咖交流圈、第一手活動(dòng)通知、限量鵝廠周邊等你來(lái)~

第一時(shí)間看鵝廠架構(gòu)設(shè)計(jì)經(jīng)驗(yàn)
評(píng)論
圖片
表情




