2010-01-07 12 views
5

Tôi muốn có thể xác định một số đối tượng và đính kèm một số "hành vi" vào đối tượng đó nơi triển khai trong hành vi không có trong đối tượng. Rails giống như: actions_as_taggable. Như một ví dụ cụ thể, tôi muốn nói rằng Nhiệm vụ có thể được gắn thẻ. Tôi không muốn phải mã hóa bất cứ điều gì trong Task về Thẻ ngoài "cho phép" hành vi thông qua ... một giao diện? Trong đó có câu hỏi của tôi. Bạn không thể đặt triển khai trong giao diện. Tôi không muốn gây ô nhiễm lớp BaseObject [trừu tượng?] Của tôi với tất cả các triển khai có thể có.C# - Làm thế nào để thực hiện nhiều "kết hợp" một cách chính xác với Giao diện và/hoặc Lớp trừu tượng

Đối tượng: công tác, Lưu ý

Hành vi:. Taggable, gửi qua email, in, Deferrable (

Một nhiệm vụ có thể được gắn thẻ, gửi qua email, in, và trì hoãn Lưu ý có thể được gắn thẻ, gửi qua email, in , nhưng không trì hoãn.

baseobject

public class BaseObject 
{ 
    Guid ID { get; set; } 
} 

tag.cs ​​

public class Tag : BaseObject 
{ 
    public Guid Id { get; set; } 
    public String Title { get; set; } 
} 

itaggable.cs

public interface ITaggable 
{ 
    void AddTag(Tag tag); 
    ... other Tag methods ... 
} 

task.cs

public class Task : BaseObject, ITaggable, IEmailable, IPrintable 
{ 
    Task specified functionality... nothing about "taggging" 
} 

note.cs

...

TagCollection.cs

public class TagCollection : List<Tag> 
{ 
    public string[] ToStringArray() 
    { 
     string[] s = new string[this.Count]; 
     for (int i = 0; i < this.Count; i++) 
      s[i] = this[i].TagName; 
     return s; 
    } 

    public override string ToString() 
    { 
     return String.Join(",", this.ToStringArray()); 
    } 

    public void Add(string tagName) 
    { 
     this.Add(new Tag(tagName)); 
    } 

Thực hiện ITaggable trông giống như

{ 
    private TagCollection _tc; 
    private TagCollection tc 
    { 
     get 
     { 
      if (null == _tc) 
      { 
       _tc = new TagCollection(); 
      } 
      return _tc; 
     } 
     set { _tc = value; } 
    } 

    public void AddTag(Tag tag) 
    { 
     tc.Add(tag); 
    } 

    public void AddTags(TagCollection tags) 
    { 
     tc.AddRange(tags); 
    } 

    public TagCollection GetTags() 
    { 
     return tc; 
    } 
} 

Vì vậy, các/cách chính xác nhất để làm điều này là những gì?

Jason

Trả lời

0

Thật không may bạn sẽ phải thêm một số mã vào lớp học của bạn, lớp cơ sở hoặc hậu duệ.

Tuy nhiên, bạn có thể thoát khỏi lớp "có thể gắn thẻ" là thành viên riêng tư và chỉ chuyển tất cả các cuộc gọi phương thức đến đối tượng thành viên đó, nhưng bạn vẫn cần triển khai giao diện.

Something như thế này:

interface ITaggable { 
    void AddTag(String tag); 
} 

class TaggableImplementation : ITaggable { 
    private Hashset<String> tags = new Hashset<String>(); 
    public void AddTag(String tag) { tags.Add(tag); } 
} 

class TaggableClass : ITaggable { 
    private ITaggable taggable = new TaggableImplementation(); 

    public void AddTag(String tag) { taggable.AddTag(tag); } 
} 
2

Cũng có rất nhiều cách tùy thuộc vào cách bạn muốn thực hiện.Trong ví dụ của bạn nó có thể là tốt hơn để làm điều gì đó dọc theo dòng này:

public interface IBehavior 
{ 
    ... common behavior methods like maybe 
    bool Execute(object value) 
} 

public class Taggable : IBehavior 
{ 
    ... tag specific items 
    public bool Execute(object value) { ... } 
} 

public class Note 
{ 
    public List<IBehavior> Behaviors { get; set; } 
    public void ProcessNote() 
    { 
     this.Behaviors(d=>d.Execute(this)); 
    } 
} 

Sự thay đổi này sẽ cho phép bạn luôn thêm hành vi hơn mà không cần phải làm bất cứ thay đổi mạnh mẽ cho các cấu trúc lớp của bạn, hoặc như thực hiện một giao diện trên mỗi lớp mà bạn muốn hỗ trợ hành vi mới. Bạn có thể muốn tìm ra những gì đối tượng chung của bạn sẽ nằm trong lớp hành vi của bạn để làm cho nó dễ sử dụng hơn cho kịch bản của bạn. Vì vậy, bạn có thể sử dụng Generics để cho phép bạn làm một định nghĩa được đánh máy hơn.

Bạn cũng có thể muốn xem mẫu trang trí để cung cấp cho bạn nhiều ý tưởng hơn nữa.

+0

Thú vị, tôi sẽ phải suy nghĩ về điều này một số chi tiết. – user166255

0

Tôi đã triển khai mixin trong C# bằng cách sử dụng các lớp một phần và sao chép mã nguồn từ một tệp mẫu vào các tệp nguồn lớp một phần. Nếu bạn chấp nhận một vài hạn chế, nó hoạt động khá tốt. Tôi đã thử bộ xử lý trước T4 để tự động tạo các tệp nguồn, nhưng nó hơi quá cồng kềnh, vì vậy tôi đã viết một công cụ khá đơn giản để sao chép mã từ các tệp mẫu dễ tạo hơn các kịch bản lệnh T4 dễ dàng hơn nhiều. Với một chút cẩn thận, bạn thậm chí có thể sử dụng Intellisense khi viết mẫu của bạn.

Đối với công cụ này, có một cái nhìn tại địa chỉ:

http://myxin.codeplex.com/

Đối với một ví dụ, có một cái nhìn vào mã nguồn cho Streambolics.Gui tại địa chỉ:

http://streambolicscore.codeplex.com/

+0

Tốt, tôi sẽ chexx0r cách tiếp cận của bạn. ;-) – herzmeister

+0

Trông đẹp hơn T4. – user166255

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