2010-09-03 25 views
11

Điều này có cho bất kỳ mã nào có mùi hoặc vi phạm nguyên tắc SOLID không?Phương pháp này có vi phạm RẮN hay có mùi mã không?

public string Summarize() 
{ 
IList<IDisplayable> displayableItems = getAllDisplayableItems(); 
StringBuilder summary = new StringBuilder(); 

foreach(IDisplayable item in displayableItems) 
{ 
    if(item is Human) 
     summary.Append("The person is " + item.GetInfo()); 

    else if(item is Animal) 
     summary.Append("The animal is " + item.GetInfo()); 

    else if(item is Building) 
     summary.Append("The building is " + item.GetInfo()); 

    else if(item is Machine) 
     summary.Append("The machine is " + item.GetInfo()); 
} 

return summary.ToString(); 
} 

Như bạn thấy, Tóm tắt của tôi() được gắn với các lớp học thực hiện như con người, động vật, vv

Liệu nó có mùi? Tôi có vi phạm LSP không? Bất kỳ nguyên tắc SOLID nào khác?

Trả lời

1

Với những nhận xét trên this answer từ OP nhiều, tôi nghĩ rằng cách tiếp cận tốt nhất là để tạo ra một lớp container tùy ý thay thế IList<IDisplayable> displayableItems trong đó có phương pháp như containsHumans()containsAnimals() để bạn có thể đóng gói các phi icky mã đa hình ở một nơi và giữ logic trong hàm Summarize() của bạn sạch sẽ.

class MyCollection : List<IDisplayable> 
{ 
    public bool containsHumans() 
    { 
     foreach (IDisplayable item in this) 
     { 
      if (item is Human) 
       return true; 
     } 

     return false; 
    } 

    // likewise for containsAnimals(), etc 
} 

public string Summarize() 
{ 
    MyCollection displayableItems = getAllDisplayableItems(); 
    StringBuilder summary = new StringBuilder(); 

    if (displayableItems.containsHumans() && !displayableItems.containsAnimals()) 
    { 
     // do human-only logic here 
    } 
    else if (!displayableItems.containsHumans() && displayableItems.containsAnimals()) 
    { 
     // do animal-only logic here 
    } 
    else 
    { 
     // do logic for both here 
    } 

    return summary.ToString(); 
} 

Tất nhiên, ví dụ của tôi quá đơn giản và không bị xâm phạm.Ví dụ, hoặc là một phần của logic trong Summarize() câu lệnh if/else của bạn, hoặc có lẽ xung quanh toàn bộ khối, bạn sẽ muốn lặp qua bộ sưu tập displayableItems. Ngoài ra, bạn có thể sẽ có hiệu suất tốt hơn nếu bạn ghi đè lên Add()Remove() trong MyCollection và yêu cầu họ kiểm tra loại đối tượng và đặt cờ, vì vậy chức năng containsHumans() của bạn (và những thứ khác) có thể đơn giản trả về trạng thái của cờ và không có để lặp lại bộ sưu tập mỗi khi chúng được gọi.

+0

Cảm ơn bạn đã trả lời, nhưng tôi không hoàn toàn hiểu được tính kỹ thuật, vì vậy bạn có thể cho tôi một ví dụ về nó không? :) cảm ơn một lần nữa, điều này có thể chính xác những gì tôi cần. Tôi chỉ cần xem một ví dụ về nó. –

+0

hmm ... thực tế là bạn chấp nhận nó có nghĩa là bạn không cần một ví dụ? Tôi rất vui khi cố gắng cung cấp một cái, nhưng tôi không hoàn toàn chắc chắn phần nào khiến bạn bối rối. Nếu bạn có thể cụ thể hơn, tôi sẽ thử. – rmeador

+0

Tôi chấp nhận nó như một câu trả lời, bởi vì nó trả lời câu hỏi cụ thể của tôi. Tôi đang làm việc trên một giải pháp dựa trên điều này. Tôi chỉ cần một ví dụ để đảm bảo rằng tôi hiểu được tính kỹ thuật. Câu trả lời của Justin dưới đây rất phức tạp và hữu ích, vì vậy một cái gì đó tương tự như nó sẽ là tuyệt vời. –

20

Tôi ngửi thấy một chút gì đó ...

Nếu tất cả các lớp của bạn thực thi IDisplayable, mỗi người nên thực hiện logic riêng của mình để tự hiển thị. Bằng cách đó vòng lặp của bạn sẽ thay đổi một cái gì đó nhiều bụi:

public interface IDisplayable 
{ 
    void Display(); 
    string GetInfo(); 
} 

public class Human : IDisplayable 
{ 
    public void Display() { return String.Format("The person is {0}", 
     GetInfo()); 

    // Rest of Implementation 
} 

public class Animal : IDisplayable 
{ 
    public void Display() { return String.Format("The animal is {0}", 
     GetInfo()); 

    // Rest of Implementation 
} 

public class Building : IDisplayable 
{ 
    public void Display() { return String.Format("The building is {0}", 
     GetInfo()); 

    // Rest of Implementation 
} 

public class Machine : IDisplayable 
{ 
    public void Display() { return String.Format("The machine is {0}", 
     GetInfo()); 

    // Rest of Implementation 
} 

Sau đó, bạn có thể thay đổi vòng lặp của bạn để một cái gì đó sạch hơn nhiều (và cho phép các lớp học để thực hiện logic hiển thị của riêng mình):

foreach(IDisplayable item in displayableItems) 
    summary.Append(item.Display()); 
+0

Cảm ơn, nhưng nếu tôi phải có một loại logic nào đó trong phương thức Summarize() để xem loại mục IDisplayable nào có trong danh sách? Tôi đoán câu hỏi của tôi là liệu thực tiễn không tốt là kết hợp Summarize() với các lớp triển khai cụ thể. –

+2

@SP - Có. Nếu bạn đang buộc các hành vi của Summarize() để triển khai cụ thể, bạn đang thực sự phủ nhận những lợi ích của việc điều trị các đối tượng đa hình thông qua giao diện IDisplayable. Nếu hành vi cần thay đổi trong Tóm tắt, nó sẽ làm như vậy thông qua các thành viên của giao diện IDisplayable. –

+0

@SP, có thể giải thích thêm những gì bạn muốn làm. Ví dụ: IDisplayable có thể có 1000 loại triển khai, nhưng bạn chỉ quan tâm đến 5 loại trong số đó. –

5

có vẻ như IDisplayable nên có một phương pháp cho tên hiển thị để bạn có thể giảm bớt phương pháp mà một cái gì đó giống như

summary.Append("The " + item.displayName() + " is " + item.getInfo()); 
+0

Chào mừng bạn đến với StackOverflow, tận hưởng kỳ nghỉ của bạn và nhớ để tip phục vụ bàn của bạn. Cũng cố gắng sử dụng định dạng mã thích hợp khi có thể! –

1

Làm thế nào về:

summary.Append("The " + item.getType() + " is " + item.GetInfo()); 
3

Có.

Tại sao không phải mỗi lớp thực hiện một phương pháp từ IDisplayable cho thấy loại của họ:

interface IDisplayable 
{ 
    void GetInfo(); 
    public string Info; 
} 
class Human : IDisplayable 
{ 
    public string Info 
    { 
    get 
    { 
     return "";//your info here 
    } 
    set; 
    } 

    public void GetInfo() 
    { 
     Console.WriteLine("The person is " + Info) 
    } 
} 

Sau đó chỉ cần gọi phương thức của bạn như sau:

foreach(IDisplayable item in displayableItems) 
{ 
    Console.WriteLine(item.GetInfo()); 
} 
1

Tối thiểu vi phạm LSP và Open- Nguyên tắc đóng.

Giải pháp là phải có một tài sản để giao diện IDisplayableDescription, vì vậy Tóm tắt mà chỉ có thể gọi

summary.Append(string.Format("The {0} is {1}", item.Description, item.GetInfo())); 

này cũng có thể được giải quyết thông qua phản ánh, vì bạn chỉ nhận được tên của lớp.

Giải pháp tốt hơn là trả lại thứ gì đó như là IDisplayableInfo từ phương thức GetInfo(). Đây sẽ là một điểm mở rộng để giúp bảo toàn OCP.

+0

Bạn có thể giải thích ngắn gọn tại sao nó vi phạm LSP không? Tôi hiểu nó vi phạm OCP. Điều gì xảy ra nếu tôi có logic bổ sung trong Tóm tắt() để kiểm tra loại lớp triển khai nào? –

+0

@SP Có thể có sự phân biệt tinh tế ở đây. Một cách phổ biến mà nguyên tắc được nói là 'Các hàm sử dụng con trỏ hoặc tham chiếu đến các lớp cơ sở phải có khả năng sử dụng các đối tượng của các lớp dẫn xuất mà không biết nó." Điều gì "không biết" nghĩa là gì? Trong một nghĩa nào đó, phương thức của bạn làm việc với bất kỳ việc thực hiện 'IDisplayable' nào - nó sẽ biên dịch và sẽ không ném một ngoại lệ. Trong một ý nghĩa khác, nó không hoạt động bởi vì nó phải "biết" việc thực hiện để làm điều gì đó có ý nghĩa với 'IDisplayable'. – Jay

0

Nếu bạn không thể sửa đổi IDisplayable hoặc triển khai lớp và bạn đang sử dụng .NET 3.5 hoặc mới hơn, bạn có thể sử dụng phương pháp mở rộng. Nhưng đó không phải là tốt hơn

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