(غير) قوانين الكود الرائع: قانون ديميتر (مع أمثلة في TypeScript)

عندما علمت عن هذه المبادئ ، شعرت بمرونة الكود الخاص بي x2 ، وسرعة اتخاذ القرار بشأن تصميم الكيانات x5.



إذا كانت 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



اقرأ هذا الخط من التعليقات ، فيه نحنمخبأ نقوم بتحليل حالة مضاءة بشكل غير كامل بمزيد من التفصيل في هذه المقالة



All Articles