桥梁设计模式造成了太多的泛型

我目前正在为Minecraft开发一些东西,而且我正在使用桥接模式,所以我的代码可以和两个独立的服务器平台(Sponge和Bukkit)一起使用,但是它们有不同的API(但有点相似)。

我有我的核心代码,这只取决于我后面需要的Minecraft中常见的东西的抽象,比如玩家和物品,以及抽象工厂和建造者类。 特定服务器平台的代码将实现工厂和构建器,并将它们作为依赖关系提供给核心代码。

到目前为止,这一直工作得很好,但我遇到了一个相互依赖的抽象问题。 例如,我有适用于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

编辑:那么,这不是一个桥梁模式?

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

这是我目前的解决方案。 如果您看到有任何改进的余地,请分享您的见解。 这里有一些我的源代码,简化了,写在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()) } } 

类型安全的代价已经消除了仿制药的需求。 PlayerAdapter.openInventory()可以通过传递一个InventoryAdapter对象作为参数来调用。 如果PlayerAdapter是一个SpongePlayerAdapter ,并且InventoryAdapter是一个SpongeInventoryAdapter ,那么SpongeInventoryAdapter unwrap()方法将返回一个海绵Inventory ,并按照预期为玩家打开库存。

例如,如果BukkitInventoryAdapter对象,则会在运行时抛出一个转换异常,因为unwrap unwrap()方法将尝试将Bukkit Inventory转换为海绵Inventory 。 这不是一个大问题,只要依赖注入正确,不应该导致错误。

Interesting Posts