إذا كانت SOLID عبارة عن مجموعة من المبادئ لكتابة رمز الجودة ، فإن قانون Demeter (LoD) و Tell Don't Ask (TDA) هما حيل محددة لتحقيق SOLID.
اليوم سنتحدث عن قانون ديميتر ("قانون ديميتر").
مبالغ فيه
يساعد هذا المبدأ في تحديد: "كيف سأحصل على كائنات متداخلة / أعدلها" - قابل للتطبيق في اللغات حيث يمكنك تعريف "الفئات" بالخصائص والطرق.
غالبًا ما تنشأ حالة عندما نحصل من مكان ما (على سبيل المثال ، من طلب HTTP) على معرف الكيان ʻa` ، ونتبعه إلى قاعدة البيانات ومن الكيان ʻa` نحتاج إلى الحصول على / تغيير الكيان `b` باستدعاء الطريقة` الطريقة`.
هكذا تقول ويكيبيديا :
ينتهك كود `` abMethod () `قانون ديميتر ، وكود الطريقة ()` صحيحة.
مثال
المستخدم لديه مشاركات بها تعليقات. تريد تلقي "تعليقات آخر مشاركة".
يمكنك تقديم هذا:
const posts = user.posts
const lastPostComments = posts[posts.length-1].comments
او مثل هذا:
const userLastPostComments = user.getPosts().getLast().getComments()
المشكلة: يعرف الكود التسلسل الهرمي الكامل للبيانات المتداخلة ، وإذا تغير هذا التسلسل الهرمي / يتوسع ، أينما تم استدعاء هذه السلسلة ، فسيتعين عليك إجراء تغييرات (إعادة تشكيل الكود + الاختبارات).
لحل المشكلة ، قم بتطبيق LoD:
const userLastPostComments = user.getLastPostComments()
ولكن بالفعل في " المستخدم " نكتب:
class User {
// ...
getLastPostComments(): Comments {
return this.posts.getLastComments()
}
// ...
}
نفس القصة مع إضافة تعليق. نحن من:
const newComment = new Comment(req.body.postid, req.body.content)
user.getPosts().addComment(newComment)
أو ، إذا كنت تريد التباهي بتشخيصك:
const newComment = new Comment(req.body.postid, req.body.content)
const posts = user.posts
posts[posts.length-1].comments.push(newComment)
تحويل هذا إلى هذا:
const posts = user.addCommentToPost(req.body.postid, req.body.content)
و " المستخدم " :
class User {
// ...
addCommentToPost(postId: string, content: string): void {
// The cleanest
const post = this.posts.getById(postId)
return post.addComment(content)
}
// ...
}
توضيح: ` Comment` جديدة يمكن أن تنشأ خارج` user` أو ` post` ، كل هذا يتوقف على كيفية ترتيب منطق التطبيق الخاص بك، ولكن أقرب إلى مالك الكيان (في هذه الحالة،` post` )، كان ذلك أفضل.
ماذا تعمل، أو ماذا تفعل؟
نحن إخفاء تفاصيل التنفيذ، وإذا من أي وقت مضى كان هناك تغيير / تمديد التسلسل الهرمي (على سبيل المثال، فإن المواقف لا تكمن فقط في `ممتلكات الوظائف ') لديك فقط لريفاكتور وmethod` getLastPostComments ` / ` addCommentToPost ` وإعادة كتابة وحدة اختبار هذه الطريقة فقط.
ما هي العيوب
الكثير من الإضافات الشفرة.
في المشاريع الصغيرة ، ستكون معظم الطرق مجرد " getter " / " setter " .
متى يجب استخدام
(1) يعد LoD مفيدًا للنماذج أو الكيانات أو المجاميع أو الفئات التي لها اتصالات عميقة / معقدة / مدمجة.
(2) يتطلب الكود المفهوم: "احصل على تعليقات المنشور الأخير " - ومشاركاتك ليست في الخاصية الأولى ، ولكن في 2 أو أكثر ، إذن ، بالتأكيد ، تحتاج إلى إنشاء طريقة ` getLastPostComments` ودمج عدة خصائص مع خصائص مختلفة المشاركات.
(3) أحاول استخدام هذا المبدأ قدر الإمكان عندما يتعلق الأمر بتحويل (تغيير ، إنشاء ، حذف) البيانات. وأقل في كثير من الأحيان عندما يتعلق الأمر باسترداد البيانات.
(4) على أساس الفطرة السليمة.
اختراق الحياة
بدأ الكثيرون في القلق بشأن عدد طرق البروكسي ، لذا إليك تبسيط: من
أجل عدم إنشاء عدد لا حصر له من طرق الوكيل ، يمكن استخدام LoD في فئة المستوى الأعلى (في حالتنا ، "المستخدم") ، وداخل التطبيق يكون بالفعل مخالفًا للقانون. على سبيل المثال:
const userLastPostComments = user.getLastPostComments()
class User {
// ...
getLastPostComments(): Comments {
// LoD, Post
const lastPost = this.posts[this.posts.length-1]
return lastPost.comments
}
// ...
}
بمرور الوقت ، إذا نمت `post` ، فسيكون من الممكن جعلها تابعة لـ getLast () ʻor` getLastComments () وهذا لن يتطلب الكثير من إعادة البناء.
ما هو المطلوب لهذا
يعمل LoD بشكل جيد إذا كان لديك شجرة تبعية / تسلسل هرمي مناسب للكيان.
ماذا تقرأ
(1) https://qna.habr.com/q/44822
تأكد من قراءة جميع تعليقات وتعليقات التعليقات (قبل التعليق Vyacheslav GolovanovSLY_G) ، تذكر أن هناك أمثلة صحيحة وغير صحيحة
(2) https://ru.wikipedia.org/wiki/Zakon_Demeter
(3) مقال
ملاحظة
يمكنني أن أفسد بعض التفاصيل / الأمثلة أو أشرح أنها ليست واضحة بما يكفي ، لذا اكتب في التعليقات التي لاحظتها ، وسأقوم بإجراء تغييرات. الامور جيدة.
PPS
اقرأ هذا الخط من التعليقات ، فيه نحنمخبأ نقوم بتحليل حالة مضاءة بشكل غير كامل بمزيد من التفصيل في هذه المقالة