2016-03-10 19 views
5

Hãy bắt đầu với Wikipedia:Luật Demeter là gì?

Nhiều chính thức, Luật của Demeter cho các chức năng đòi hỏi một phương pháp m của một đối tượng O chỉ có thể gọi các phương pháp của các loại sau đây của các đối tượng:

  1. O tự
  2. tham số m của
  3. Bất kỳ đối tượng được tạo/instantiated trong m
  4. thành phần trực tiếp 63.210
  5. O của các đối tượng
  6. Một biến toàn cầu, truy cập bằng O, trong phạm vi của m

Quy tắc 1:

public class ClassOne { 

    public void method1() { 
     method2(); 
    } 

    public void method2() { 

    } 
} 

Quy tắc 2:

public class ClassOne { 

    public void method1(ClassTwo classTwo) { 
     classTwo.method2(); 
    } 
} 

class ClassTwo { 

    public void method2() { 

    } 
} 

Quy tắc 3:

public class ClassOne { 

    public void method1() { 
     ClassTwo classTwo = new ClassTwo(); 
     classTwo.method2(); 
    } 
} 

class ClassTwo { 

    public void method2() { 

    } 
} 

Quy tắc 4 (nhờ @juharr):

public class ClassOne { 

    private ClassTwo classTwo; 

    public void method1() { 
     classTwo = new ClassTwo(); 
     classTwo.method2(); 
    } 
} 

class ClassTwo { 

    public void method2() { 

    } 
} 

Quy tắc 5:

? 

bất cứ ai có thể giúp tôi với Quy tắc 5?


Và không phải luật Demeter ngụ ý rằng chuỗi là xấu?

User.getName().getLastName(); 

Điều này dẫn đến kết nối cao.


Không phải "Kể, đừng hỏi" một nguyên tắc tương tự?

Vì vậy, đây là tất cả mọi thứ? Tôi có sai về điều gì đó không? Làm thế nào bạn có thể tuân theo Luật Demeter?

+0

Có, về cơ bản "demeter" có thể được đọc để nói: chuỗi là xấu. Bạn không nhận được một cái gì đó để có được một cái gì đó từ đó để làm một cái gì đó về điều cuối cùng. – GhostCat

+2

Quy tắc 4 là nếu 'ClassOne' có một trường riêng (thành phần) của kiểu' ClassTwo', thì bạn có thể gọi các phương thức trên trường đó từ phương thức của bạn trong 'ClassOne'. – juharr

+0

@juharr Cảm ơn! – Anonymous

Trả lời

3

"Kể cho đừng hỏi" có một chút khác biệt.

Demeter: không tìm được thứ gì đó để làm điều gì đó cho điều cuối cùng.

TDA: không truy xuất "thông tin" từ một đối tượng khác để sau đó đưa ra quyết định về điều đó. ví dụ đơn giản:

if (someList.size() == 0) { bla 

vs

if (someList.isEmpty()) { bla 

Trong cả hai trường hợp, bạn đang kêu gọi một phương pháp trên một số đối tượng khác; nhưng có một sự khác biệt chính: cuộc gọi đầu tiên cho thấy trạng thái "bên trong" của đối tượng kia đối với bạn; mà sau đó bạn đưa ra quyết định.Trong khi đó, trong "TDA" cải thiện phiên bản thứ hai; bạn để lại rằng "đánh giá trạng thái" trong đối tượng kia; do đó bằng cách nào đó giảm khớp nối.

2

Thứ năm rất khó thể hiện trong C# hoặc Java, vì chúng không hỗ trợ kỹ thuật các biến toàn cầu. Tuy nhiên, trong một mẫu thiết kế tương tự về nguyên tắc, bạn có thể có, ví dụ: một lớp cấu hình mà chỉ chứa các giá trị cấu hình tĩnh trên thế giới có thể truy cập, chẳng hạn như (C#):

internal class MyConfiguration 
{ 
    private static String MyConfigurationValue; // set in constructor 
    MyConfiguration(){ MyConfigurationValue = DoSomethingToLoadValue(); } 
    public static String GetMyConfigurationValue(){ return MyConfigurationValue; } 
} 

Trong trường hợp này (giả sử các mẫu thiết kế là chấp nhận được trong tất cả các cách khác), Luật của Demeter sẽ cho phép điều này, vì nó có thể truy cập trên toàn cầu và có ý định như vậy.

+0

Vì vậy, trường "MyConfigurationValue" có được công khai không? – Anonymous

+0

@Robiow Không có trong ví dụ này, bởi vì điều này cho thấy cách cung cấp thông tin cấu hình theo cách toàn cầu, nhưng chúng tôi không muốn các lớp khác có thể thay đổi nó, dù vô tình hoặc có mục đích. Nói chung, khi bạn cho phép cả đọc và sửa đổi các thuộc tính, làm cho trường công khai là cần thiết (đối với những người ủng hộ cách tiếp cận "thuộc tính", tôi chỉ ra rằng các thuộc tính chủ yếu chỉ là một cách lén lút để có thể nói rằng tất cả biến thành viên là riêng tư, mặc dù chúng hoạt động như thể chúng là công khai, thông qua các phương thức thêm phí phía sau hậu trường để công khai chúng). –

1

Một ví dụ cho Rule 5 sẽ là:

public class ClassOne { 
    public void method1() { 
     classTwo.STATIC_INSTANCE.method2(); 
    } 
} 

class ClassTwo { 
    public static final ClassTwo STATIC_INSTANCE = ...; 

    public void method2() { 
    } 
} 

Enums về cơ bản làm việc theo cách này, và đó là ok enums truy cập.


dụ của bạn:

user.getName().getLastName(); 

rõ ràng mâu thuẫn với pháp luật, kể từ khi đối tượng bạn nhận được từ "getName()" sẽ không rơi vào bất kỳ các loại được liệt kê. Lưu ý: điều này là sai ngay cả khi bạn không sử dụng cuộc gọi theo chuỗi:

Name name = user.getName(); 
name.getLastName(); // <- this is still wrong 

vì đối tượng "tên" vẫn không rơi vào bất kỳ danh mục được liệt kê nào.

Tuy nhiên mọi thứ như thế này là ok:

reportBuilder.withMargin(5).withFooter(10) 
    .withBorder(Color.black).build(); 

Tại sao được phép điều này? Bởi vì bạn có thể nhận được cùng một đối tượng (reportBuilder) trở lại mỗi lần, hoặc có thể là một đối tượng mới mỗi lần nếu trình xây dựng được triển khai như là không thay đổi. Dù bằng cách nào, nó rơi vào pháp luật 2 hoặc 3, vì vậy nó là ok một trong hai cách.


Câu hỏi thứ ba của bạn là "cách tuân theo". Vâng, đây là một câu hỏi phức tạp, nhưng chỉ để bắt đầu, suy nghĩ về những loại phương pháp thực sự bị cấm bởi luật pháp!

Chỉ cần đặt luật thành tiêu cực: Chúng ta không nên gọi phương thức trên đối tượng đã có (vì đối tượng mới được miễn) và không phải đối tượng của tôi hoặc trường của đối tượng hoặc tham số của tôi. Vì vậy, để lại các đối tượng nằm trong các trường các đối tượng khác! Vì vậy, về cơ bản điều đó có nghĩa là bạn không nên "truy cập" vào các đối tượng không phải là bạn, không phải trong các trường của bạn, chứ không phải là các tham số trực tiếp. Mà tôi sẽ tóm tắt là "không có getters"!

Các vấn đề liên quan