3

我处于一种情况,我有一个里面Bag有一个AddSlot方法。我有两种类型的包,ItemsBagDCBag代表可拖动内容) ItemsBag是一个 2D 包,这意味着它有行和列,DCBag是 1D,它只有一列但有很多行(这意味着我也可以将其视为 2D)。

现在的问题是,由于第一个包处理 2D 索引,我希望AddSlot签名是这样的:

public void AddSlot(int r, int c);

还有另一个包的AddSlot

public void AddSlot(int r);

如何编写 in 的虚拟/抽象签名,AddSlot以便Bag何时ItemsBagDCBag继承Bag它们可以以我上面提到的方式覆盖签名?

正如我所说,我也可以DCBag将 2D 视为 2D,以便它ItemsBag具有相同的签名,但我真的很想知道我是否可以这样做,这很有趣。

我可以使用可变数量的参数逃脱,params obejct[] args但最好以不涉及装箱/拆箱的方式进行。

我也可以制作 aTwoDimBag并使OneDimBag它们都继承自Bag,按照我想要的方式在其中编写定义AddSlot,然后进行ItemsBag继承TwoDimBagDCBag继承OneDimBag,但我不是在寻找解决方法,而是如何实现我的目标要求。

再次回顾一下最后一次:我怎样才能写一个我可以在继承的孩子中覆盖的签名?(也就是说,如果我可以并且有办法)

谢谢。

编辑:(额外信息)其中Bag有很多功能。这两个包之间的区别在于它ItemsBag拥有一个 2d 的 Slot ( List<List<Slot>>) 列表,而DCBag拥有一个 1dListSlot。它Slot拥有一个Item. - 里面的物品ItemsBag可以多拿一件Slot,里面的物品DCBag只能拿一件。

你可以在两个包里做的一些事情:AddSlot, FreeSlot, AddItem(添加策略不同,还有额外的添加方法ItemsBag),在两个包中你可以用鼠标拾取物品,交换物品,分类物品,两个包也收到来自插槽的通知以采取必要的措施,例如Notify_ClickedOnEmptySlot(Slot slot)

您只能在 中执行的一些操作ItemsBag:组合项目、添加一排插槽、添加一列插槽和旋转项目。

以下是这些包在外观方面的不同之处,ItemsBag这是一个旧的演示):

在此处输入图像描述

DCBag

在此处输入图像描述

4

2 回答 2

1

如果对象是一袋物品,则考虑将物品类型设为通用

即你会有一个通用Bag<T>类:

class Bag<T>
{
     private readonly List<T> _items = new List<T>();
     public void AddSlot(T item)
     {
         _items.Add(item);
     }
}

在这种情况下,您的项目类型可以是任何东西:

class Item1D
{ 
    public int Value { get; set; }
}

class Item2D
{
    public int X { get; set; }
    public int Y { get; set; }
}

并且假设所有项目的“包”功能都相同,您将通过传递适当的泛型类型来实例化不同的包:

var bag1D = new Bag<Item1D>();
var bag2D = new Bag<Item2D>();

或者,您甚至可以将项目列表作为通用参数传递:

var bagOfSlots = new Bag<Slot>();
var bagOfListOfSlots = new Bag<List<Slot>>();

检查System.Collections.Generic命名空间中的类,这是一般的想法。此外,您是否真的需要将其设为虚拟取决于Bag该类的职责应该是什么(查看单一职责原则)。OOP 中的一条经验法则是使类的职责尽可能简单(并且“包”仅意味着项目的无序集合)。

[更新]

如果DCBag或多或少是ItemBag单列,那么您可以使用new关键字更改方法的签名,同时仍然可以访问基本方法:

class ItemBag
{
    public virtual void AddSlot(int r, int c)
    {

    }
}

class DCBag : ItemBag
{
    public new void AddSlot(int r)
    {
        // we only have a single column
        base.AddSlot(r, 0);
    }
}

请注意,这不是覆盖该方法,而是创建一个具有相同名称的新方法。换句话说,您可以调用:

ItemBag itemBag = new ItemBag();
itemBag.AddSlot(3, 4);

DCBag dcBag = new DCBag();
dcBag.AddSlot(3);

但是你不能有动态调度(我认为在这种情况下你不需要它):

// if dcBag is of type ItemBag
ItemBag dcBag;

// ...and you instantiate it to a DCBag...
dcBag = new DCBag();

// ...you still end up with a virtual signature...
dcBag.AddSlot(3, 4);

// ...and the new method is inaccessible
dcBag.AddSlot(3); // <-- this will not compile
于 2013-08-28T08:13:28.587 回答
0

您可以在基类中指定此方法并使用可选参数。

public void AddSlot(int r, int c = 0)
{
}

然后,当你这样称呼它时。

itemsBag.AddSlot(1, 1);
dcBag.AddSlot(1);

而且由于这两种类型都是 2D 的,正如你所说,你可以用同样的方式对待它们,不是吗?

更新:

根据您的评论,也在您的基类中定义

private abstract void AddSlotInternally(int r, int c);

您将在其中为您的包定义特定行为,因为它们必须覆盖它。

public void AddSlot(int r, int c = 0)
{
    AddSlotInternally(r, c);
}

我不认为这个解决方案如此糟糕,以至于其他开发人员不会理解。泛型有时比简单的基本方法更令人困惑。

于 2013-08-28T08:09:26.853 回答