[英]Combining two interfaces into one
正如我在之前的一個問題中提到的,我正在重構我正在處理的一個項目。 現在,一切都取決於其他一切。 一切都被分離到我早期創建的命名空間中,但我認為我的分離方法不是很好。 我試圖消除一個對象依賴於另一個依賴於另一個對象的不同命名空間中的另一個對象的情況。
我這樣做的方法是將我的項目(游戲)分成幾個程序集:
GameName.Engine
GameName.Rules
GameName.Content
GameName.Gui
GameName.Engine
程序集包含一堆接口,因此程序的其他部分不需要依賴於任何特定的實現。 例如,我有一個GameName.Engine.ICarryable
接口,它主要由GameName.Content.Item
類(及其子類)實現。 我還有一個對象允許Actor
拿起一個ICarryable
: PickupAction
。 Previously
,它需要一個 Item,但這暴露了不必要的方法和屬性,它實際上只需要拾取和攜帶它所需的方法。 這就是我創建ICarryable
接口的原因。
現在一切都很好,所以我的問題。 GameName.Gui
應該只依賴於GameName.Engine
,而不是任何實現。 在GameName.Gui
里面,我有一個MapView
對象,它顯示一個Map
和它上面的任何IRenderable
對象。
IRenderable
基本上只是一個暴露圖像和一些描述對象的字符串的接口。 但是, MapView 還需要該對象來實現ILocateable
,因此它可以看到它的位置並知道它何時通過ILocateable
內部的LocationChanged
事件ILocateable
。
這兩個接口由Item
和Actor
對象實現。 其中,又是在GameName.Content
中定義的。 由於它需要兩個接口,我有兩個選擇:
使GameName.Gui
依賴於GameName.Content
並需要一個Entity
( Item
和Actor
基類)。
在GameName.Engine
一個如下所示的界面:
interface ILocateableRenderable : ILocateable, IRenderable { }
然后讓我的Actor
和Item
對象實現該接口,而不是單獨實現這兩個接口。
有人對哪種方法最好有任何建議嗎? 創建一個沒有方法或屬性的接口,只強制實現另外兩個接口是否合適?
說明: MapView
在Map
,它由Entity
對象組成。 我不想將Entity
對象暴露給MapView
,它只需要知道它們的位置( ILocateable
)以及如何呈現它們( IRenderable
)。
您似乎有兩個相互矛盾的要求:
在 GameName.Gui 里面,我有一個MapView 對象,它顯示一個 Map 和它上面的任何 IRenderable對象。
和
但是, MapView 還需要該對象來實現 ILocateable ,因此它可以通過 ILocateable 內的 LocationChanged 事件查看其位置並知道其何時更改。
所以,如果 MapView 只需要 IRenderable,那么它應該接受 IRenderable,然后檢查該類是否也實現了 ILocateable。 在這種情況下使用它的方法。
public void Whatever(IRenderable renderable)
{
if (renderable is ILocateable)
{
((ILocateable) renderable).LocationChanged += myEventHandler;
}
// Do normal stuff
}
另一方面,如果您總是需要它是 ILocateable 和 IRenderable,那么您應該真正以兩種方式之一創建派生接口
interface IMappable: IRenderable, ILocateable {}
public void Whatever(IMappable mappable)
{
mappable.LocationChanged += myEventHandler;
// Do normal stuff
}
或
interface IRenderable: ILocateable
{
// IRenderable interface
}
public void Whatever(IRenderable renderable)
{
renderable.LocationChanged += myEventHandler;
// Do normal stuff
}
取決於您的代碼目前的情況。
在所有情況下,IRenderable 對象也必須實現 ILocateable,所以我正在做 @Sklivvz 建議的事情並使 IRenderable 實現 ILocateable:
public interface IRenderable : ILocateable
{
// IRenderable interface
}
這種模式在 .NET 中被大量使用。 例如,ICollection 接口實現了 IEnumerable,同時添加了其他方法。 這是對上面代碼所做的直接類比。
謝謝@Sklivvz。
您可能會考慮,但我想我不是該領域的專家,將引擎分成兩部分,一個渲染器和一個位置管理器。 然后,您可以將 ILocateable 對象添加到后者,並將 IRenderable 對象添加到前者。 但是,如果您認為這沒有任何意義和/或過於復雜,那么創建這個合並的界面似乎還不錯。 另一種選擇可能是向 ILocateable 和 IRenderable 添加一個超級接口,例如 IGameObject,您將在引擎類中接受該接口,然后檢查將對象分派到地圖、位置事物或兩者的確切類型。
選項 2 違反了接口隔離原則。 基本上客戶端不應該看到它不需要的方法......沒有胖接口。 如果一個對象不能只實現這些接口中的任何一個,那么你應該將它們組合成一個單一的接口。 但是,如果讓對象只是可 ILocatable 而不必是 IRenderable 是有意義的,請保持接口不同。 我看不出有什么問題。
您可以創建一個默認基類(同時實現兩者),以防您發現這是常見的/80% 場景
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.