2013-05-03 77 views
2

我的應用程序由獨立的服務器和客戶端組成。它們通過服務器創建和修改的對象進行通信。客戶端提供此對象的只讀接口。據我所知,這是保持封裝在OOP中的正確方法。見例如:通過通用接口進行封裝的正確方法

// Client-side 

interface IBox<T> where T : ITool 
{ 
    IEnumerable<T> Tools { get; } 
} 

interface ITool 
{ 
    void Use(); 
} 

// Server-side 

class Box : IBox<Tool> 
{ 
    public List<Tool> ToolList = new List<Tool>(); 

    public IEnumerable<ITool> Tools 
    { 
     get { return ToolList; } 
    } 
} 

class Tool : ITool 
{ 
    string _msg = "default msg"; 
    public string Msg 
    { 
     get { return _msg; } 
     set { _msg = value; } 
    } 

    public void Use() 
    { 
     Console.WriteLine("Tool used! Msg: {0}", _msg); 
    } 
} 

正如你看到的,我必須使用仿製藥,因爲我的對象形成一個層次。

,看起來不錯,直到我決定增加一個Room類接口IRoom,這不得不不僅IBox,但ITool概括太:

interface IRoom<B, T> 
    where B : IBox<T> 
    where T : ITool 
{ 
    IEnumerable<B> Boxes { get; } 
} 

class Room : IRoom<Box, Tool> 
{ 
    public List<Box> BoxList = new List<Box>(); 

    public IEnumerable<Box> Boxes 
    { 
     get { return BoxList; } 
    } 
} 

現在,假設我們有一個Room由不僅盒子。我需要至少3個完全不同的東西集合,它們也是幾種類型的集合。所以,必須有一棵巨大的樹,我的根類變得像這樣:Room : IRoom<Box, Tool1, Tool2, Tool3, Wardrobe, Coat, Jeans, Hat, Table, Computer, Book, Pen>

我不確定,那是對的。所以,我問,什麼是真正的面向對象的實現我的任務的方式? (沒有反射,打破封裝,類型轉換或其他不好的技巧)

+2

您確實需要使用泛型???他們不是要形成層次結構,而是要處理許多不同的類型。但是既然你已經有了接口,並且它看起來你所有的類型參數都需要是單一的接口類型,你可以使用避免泛型的接口。 – 2013-05-03 13:59:46

+0

我想'房間'有一個'List ',我想把每個類的對象放到房間裏實現'IRoomItem'。同樣使用「Box」和「IBoxItem」。 – Corak 2013-05-03 14:03:52

+0

@Daniel我相信我需要在主題中描述的類型安全,封裝和功能:服務器創建和修改客戶端讀取。兩者都是獨立的。請提出沒有泛型的方式 – astef 2013-05-03 14:07:12

回答

2

從.NET Framework 4和C#4開始,您可以使用IEnumerable的協方差並避免使用泛型。這裏所描述

// Client-side 

interface IBox 
{ 
    IEnumerable<ITool> Tools { get; } 
} 

interface ITool 
{ 
    void Use(); 
} 

// Server-side 

class Box : IBox 
{ 
    public List<Tool> ToolList = new List<Tool>(); 

    public IEnumerable<ITool> Tools 
    { 
     get { return ToolList; } // With .NET 3.5 and earlier cast here is neccessary to compile 
     // Cast to interfaces shouldn't be so much of a performance penalty, I believe. 
    } 
} 

class Tool : ITool 
{ 
    string _msg = "default msg"; 
    public string Msg 
    { 
     get { return _msg; } 
     set { _msg = value; } 
    } 

    public void Use() 
    { 
     Console.WriteLine("Tool used! Msg: {0}", _msg); 
    } 
} 


interface IRoom 
{ 
    IEnumerable<IBox> Boxes { get; } 
} 

class Room : IRoom 
{ 
    public List<Box> BoxList = new List<Box>(); 

    public IEnumerable<IBox> Boxes 
    { 
     get { return BoxList; } // and here... 
    } 
} 

協方差和逆變泛型:http://msdn.microsoft.com/en-us/library/dd799517.aspx

+0

我認爲列表不能是IEnumerable 而且你的代碼不會編譯......但它以某種方式。魔法。謝謝! – astef 2013-05-03 14:17:15

+0

我很驚訝,但沒有必要施放(或者我誤解了這個術語?)。我的意思是,你的代碼按原樣運作。無需調用'ToolList.Cast ()',或'(IEnumerable )ToolList' – astef 2013-05-03 14:25:20

+0

也許它會編譯但不能運行,我相信你需要做那個強制轉換。但我會選擇演員作爲比泛型更好的選擇。 – 2013-05-03 14:25:32

相關問題