有一段時間我在我的單體專案中緊密耦合了我的物件屬性。幾乎沒有 DTO。從客戶端 -> 到資料庫,它幾乎沒有關注 SOLID 原則。依賴關系向內發展,留下了更改和維護成本高昂的架構。但是,因為我已經閱讀和研究了很多關于它的 SOLID 和干凈的架構。我注意到有很多物件的重新映射以保持分離。
示例 1: DAL:重命名屬性約定 first_name => firstName。
class UserRepository {
#pool: Pool;
#tableName = 'platform_users';
constructor(pool: Pool) {
this.#pool = pool;
}
async findById(id: string): Promise<UserEntity | null> {
try {
const QueryString = `SELECT * FROM ${this.#tableName} WHERE id = $1`;
const QueryArguments = [id];
const rawData = await this.#pool.query(QueryString, QueryArguments);
const data = this.#mapPostResults(rawData);
return data.length > 0 ? data[0] : null;
} catch (e) {
throw new Error('Failed to process query');
}
}
async insertNewUser({
id,
username,
firstName,
lastName,
password,
email,
verified,
registeredOn,
lastLogin,
description
}: UserEntity): Promise<{ rowCount: number; id: string }> {
try {
const QueryString = `INSERT INTO ${
this.#tableName
}(id, first_name, last_name, email, verified, password, registered_on, last_login, description, username) VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) RETUIRNING id`;
const QueryArguments = [
id,
username,
firstName,
lastName,
email,
password,
verified,
registeredOn,
lastLogin,
description
];
const rawData = await this.#pool.query(QueryString, QueryArguments);
return { rowCount: rawData.rowCount, id: rawData.rows[0].id };
} catch (e) {
console.log(e);
throw new Error('Failed to process query');
}
}
#mapPostResults(res: QueryResult): UserEntity[] {
return res.rows.map((r) => {
return {
id: r.id,
username: r.username,
firstName: r.first_name,
lastName: r.last_name,
email: r.email,
password: r.password,
verified: r.verified,
lastLogin: r.last_login,
description: r.description,
registeredOn: r.registered_on
};
});
}
}
示例 2:express 的 req 的依賴反轉,以及我們的控制器的 res。建立一個獨立于框架(express)的介面 - 下面我們看到httpRequest將接收來自 express 的“請求結構”的關閉 1:1 映射。
export default function makeExpressCallback(controller) {
return (req: Request, res: Response) => {
const httpRequest = {
body: req.body,
query: req.query,
params: req.params,
ip: req.ip,
method: req.method,
path: req.path,
session: req.session || {},
headers: {
'Content-Type': req.get('Content-Type'),
Referer: req.get('referer'),
'User-Agent': req.get('User-Agent')
}
};
controller(httpRequest)
.then((httpResponse) => {
if (httpResponse.headers) {
res.set(httpResponse.headers);
}
res.type('json');
res.status(httpResponse.statusCode).send(httpResponse.body);
})
.catch((e) => res.status(500).send({ error: 'An unkown error occurred.' }));
};
}
// index.ts
router.post('/user', bodyParser.json(), makeExpressCallback(createUserAccount));
這些示例繼續到用例層,用于映射他們的回應和請求......
“請求和回應模型用例需要輸入資料,它們會產生輸出資料。然而,一個格式良好的用例物件不應該知道資料與用戶或任何其他組件的通信方式。我們當然不希望用例類中的代碼知道 HTML 或 SQL!
用例類接受簡單的請求資料結構作為其輸入,并回傳簡單的回應資料結構作為其輸出。這些資料結構不依賴于任何東西。它們并非源自 HttpRequest 和 HttpResponse 等標準框架介面。他們對網路一無所知,也不分享任何可能存在的用戶界面的任何陷阱。
這種缺乏依賴性是至關重要的。如果請求和回應模型不是獨立的,那么依賴它們的用例將間接系結到模型攜帶的任何依賴項。
您可能想要讓這些資料結構包含對 Entity 物件的參考。您可能認為這是有道理的,因為物體和請求/回應模型共享大量資料。避免這種誘惑!這兩個物件的目的非常[…]”
摘自清潔架構:軟體結構和設計的工匠指南(Robert C. Martin 系列) Robert C. Martin 此材料可能受著作權保護。
所以有了這個,與我以前的編碼方式相比,我不必做這些映射,因為它們在每一層(或缺少)是多么緊密地耦合,當然這很糟糕。但我確實想知道,這些型別的映射是否昂貴,我們是否仍應努力盡量減少,即使權衡顯著超過不這樣做?
uj5u.com熱心網友回復:
這些映射的成本都在開發人員時間,而不是在運行時。您正在談論在記憶體中洗牌幾個位元組,最多需要幾微秒。如果您擔心,當然應該對其進行基準測驗,只需確保基準測驗代碼本身在其性能影響方面是一致的。
RAM 訪問速度非常快,并且在 Node VM 中進行了高度優化。通常在此您傳遞對字串物件的參考,而不是實際創建新的記憶體位置。當您第一次必須從資料庫讀取額外的幾個位元組或往返瀏覽器(10 毫秒而不是幾微秒)時,所有這些都會被包含在內。
除非您要深度復制大型陣列,否則 DTO 通常會很便宜。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/513971.html
