2017-06-16 59 views
1

我目前工作的東西我的世界,而我使用橋接模式,所以我的代碼可以使用兩個獨立的服務器平臺,海綿和Bukkit,不同(但有點類似於使用)API的。造成太多的仿製藥大橋設計模式

我有我的核心代碼,這僅取決於在我的世界共同的東西,我稍後需要的,比如玩家和物品,以及抽象工廠和製造商類抽象。特定服務器平臺的代碼將實現工廠和構建器,並將它們作爲依賴關係提供給核心代碼。

這一直工作得很好,到目前爲止,但我遇到了一個問題,與互相依賴抽象。例如,我有適用於Minecraft庫存的適配器和適用於我自己的抽象項目/庫存類型的項目/庫存類型的項目。 Item和Inventory對象需要互相交互,並且由於核心代碼不知道實現,所以我使用泛型。這裏有一些僞代碼:

interface Item<TBase> { 
    TBase getBase(); 
} 
interface Inventory<TItem extends Item<*>> { 
    void addItem(TItem item); 
} 

Item類適應服務器平臺使用的項目類型中的項目。 addItem()方法實現將使用getBase()方法將服務器平臺項目的實例添加到服務器平臺的清單實例。總體而言,泛型提供了平臺特定對象之間交互的解決方案。

我已經運行到這個問題,但是,仿製藥越來越複雜的項目的大小增加。其中一個原因是使用商品/庫存的類將需要相同的泛型。例如,所有玩家都有一個庫存:

interface Player<TItem extends Item<*>> { 
    Inventory<TItem> getInventory(); 
    void giveItem(TItem item); 
} 

而使用玩家的東西需要具有泛型等等。

的第二個問題是,有不只是這兩種情況下,這可能意味着對所有使用該對象的類的對象幾個泛型參數,因而更仿製藥之間更多的互動。

我想另一種解決方案根本不會使用泛型,而是改變getBase()返回Object類型,並盲目地施放,相信它是正確的類型(它會是)。

我已經把一噸的思想到這一點,這可能是我能拿出最好的。我想知道是否有其他解決方案,我錯過了,或任何設計模式,可能有助於解決這個問題。

如果具有源會有所幫助,您可以在這裏找到: https://github.com/BenWoodworth/FastCraft/tree/master/src/main/kotlin/net/benwoodworth/fastcraft

+0

爲什麼'Player'需要與'Item'有關的通用類? '玩家'不是'物品'。 –

+0

我不確定如何確保'getInventory()'提供了一個'Inventory',其中包含'Item'的正確實現。 –

回答

0

編輯:那麼,這是不是一個橋模式?

public interface InventoryHolder 
{ 
    public void transfer(Player toPlayer, Item item); 
} 

然後

public class Player implements InventoryHolder 
{ 
    List<Item> items; 
    public Item removeItem(Item item){ 
     return items.remove(items.indexOf(item)); 
    } 
    public void addItem(Item item) { 
     items.add(item); 
    } 
    public void transfer(Player toPlayer, Item item) 
    { 
     toPlayer.addItem(removeItem(item)); 
    } 
} 

public class Item {} 

所以

public class PlayGame 
{ 
    public static void main(String... args) { 
     new PlayGame().run(); 
    } 
    private void run() { 
     Player p1 = new Player(); 
     Player p2 = new Player(); 
     Item item = new Item(); 
     p1.addItem(item); 
     // transfer 
     p1.transfer(p2, item); 
    } 
} 
+0

我有'SpongeItemBuilder'和'BukkitItemBuilder'實現的抽象依賴項'ItemBuilder',用於爲各個平臺(而不是'new Item()')構建項目。假設玩家的「庫存」是BukkitInventory的具體實現,它調整** Bukkit **庫存對象。如果我使用'SpongeItemBuilder'構建一個'Item',沒有類型安全阻止我試圖將'Item'(適應** Sponge **項)添加到** Bukkit **清單。來自正在改編的Bukkit API的廣告資源無法接受來自** Sponge ** API的項目。 –

+0

老實說這個問題是一個設計'意見'的問題,不屬於SO。我會鼓勵你退後一步並着手「2.0版」。一個人是一個對象,所以我認爲這不是一般意義。它可能是一個基類,但泛型類往往會對事物起作用,就像列表存儲事物一樣。所以,你有一點誤入歧途,需要重新啓動。 –

+0

我的想法是,抽象玩家攜帶一個泛型類型的項目,因爲列表包含泛型類型的對象。總的來說,我在問,因爲我想看看是否有一種標準的方法來橋接API與這樣的交互,這樣我就可以用一種更好的方法來反思我的不可思議。 2.0版本的種類。 –

0

這是我目前的解決方案。如果您看到有任何改進的餘地,請盡情分享您的見解。這裏有一些我的源代碼,簡化了,寫在Kotlin中。

依賴關係:

// An abstract class, to be used by objects adapting 
// native implementations. Provides an unwrap method, 
// to unwrap the adapted object. 
abstract class Adapter(protected val base: Any) { 
    @Suppress("UNCHECKED_CAST") 
    fun <T> unwrap() = base as T 
} 

// Inventory adapter, extends Adapter 
abstract class InventoryAdapter(baseInventory: Any) : Adapter(baseInventory) 

// Player adapter, extends Adapter 
abstract class PlayerAdapter(basePlayer: Any) : Adapter(basePlayer) { 
    abstract fun openInventory(inventory: InventoryAdapter) 
} 

海綿執行:

// Adapts Player (from the Sponge API) 
class SpongePlayerAdapter(
     protected val basePlayer: Player 
): PlayerAdapter(basePlayer) { 

    override fun openInventory(inventory: InventoryAdapter) { 
     // The unwrap<T>() method inferences T as Sponge's 
     // Inventory type, from the openInventory parameter 
     basePlayer.openInventory(inventory.unwrap()) 
    } 
} 

需要仿製藥已被刪除,在類型安全的成本。可以通過傳入InventoryAdapter對象作爲參數來調用PlayerAdapter.openInventory()。如果PlayerAdapterSpongePlayerAdapter,並且InventoryAdapterSpongeInventoryAdapter,則該方法將返回海綿Inventory,並且如預期地爲玩家打開庫存。

如果BukkitInventoryAdapter對象進行傳遞,例如鑄造異常會在運行時被拋出,因爲unwrap()方法將嘗試施放Bukkit Inventory到海綿Inventory。這不是一個大問題,只要依賴關係被正確注入就不應該導致錯誤。