2010-01-07 61 views
5

我希望能夠定義一些對象並將一些「行爲」附加到該對象中的行爲不在對象中的行爲。 Rails就像:acts_as_taggable。作爲一個具體的例子,我想說任務可以被標記。我不想在任務中編寫任何有關通過...接口「啓用」行爲的代碼的任何內容嗎?這是我的問題。你不能把實現放在一個接口中。我不想污染我的BaseObject [抽象?]類與所有的可能的實現。c# - 如何使用接口和/或抽象類正確地執行MULTIPLE「mixins」

對象:任務,注意

行爲:可加標籤,通過電子郵件發送,可印刷,可延遲(

任務可被標記,通過電子郵件發送,打印和推遲 的註記可被標記,通過電子郵件發送,打印,而不是推遲。

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)); 
    } 

ITaggable的實現看起來像

{ 
    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; 
    } 
} 

那麼什麼是做到這一點的正確/最佳方法是什麼?

傑森

回答

0

不幸的是你將不得不一些代碼添加到您的課,無論是基類或後裔。

但是,您可以避開「taggable」類作爲私有成員,只是將所有方法調用傳遞給該成員對象,但仍需要實現該接口。

事情是這樣的:

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

那麼有很多方法取決於您希望如何實現。在您的例子可能會更好做沿着此線的東西:

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)); 
    } 
} 

這種變化將允許你隨時添加更多的行爲,而無需做任何劇烈的變化,以您的類結構要麼喜歡實現上的接口每一個你想要支持新行爲的班級。你可能想知道你的行爲類中的共同對象是什麼,以使它更容易用於你的場景。所以你可以使用泛型來讓你做更多類型的定義。

您可能也想看看Decorator模式,以便給您更多的想法。

+0

有趣的是,我將不得不多想一想這個。 – user166255 2010-01-13 19:33:01

0

我已經使用部分類在C#中實現了mixins,並將源代碼從模板文件複製到部分類源文件中。如果你接受一些限制,它的效果很好。我嘗試了T4預處理器來自動生成源文件,但它有點太麻煩,所以我寫了一個相當簡約的工具來從模板文件中複製代碼,這些模板文件比T4腳本更容易生成。稍加小心,編寫模板時甚至可以使用Intellisense。

對於工具,看看:

http://myxin.codeplex.com/

有關示例,看看爲Streambolics.Gui的源代碼在:

http://streambolicscore.codeplex.com/

+0

不錯,我會用我們的方法來幫助你。 ;-) – herzmeister 2010-01-09 17:33:37

+0

看起來比T4好。 – user166255 2010-01-13 19:31:24