OOP嵌套类和辅助函数的最佳设计实践

时间:2017-06-04 00:00:28

标签: c# oop

我正在用C#编写一个项目,我对OOP最佳实践有两个问题。为了简化我的问题,我简化了代码示例。

我有一个类Map,它将信息保存到2D平铺图中。 Map类只有一个实例:

class Map {
    int height
    int width
    InventoryGrid iGrid
    TileGrid tGrid

    public Map(int height, int width) { ... }
}

Map类包含2个与地图上的项目和图块相关的网格。这些是技术上嵌套的类,因为它们不会在代码中的任何其他位置初始化。例如,InventoryGrid类可能如下所示:

class InventoryGrid {
    Dictionary<int, Item> inventory

    public function SetInventory(int index, item) { ... }
    public function GetInventory(int index) { ... }
}

假设我们有一个Job类,如果操作完成,则需要更新库存。

class Job {
    public void FinishedJob()
    {
        // I need to update the inventory.
    }
}

我们假设Job类进行事件调用或有权访问Map实例。

第一个问题是,在内部类上调用InventoryGrid.SetInventory()函数的最佳OO方式是什么:

  1. Map类中创建一个getter函数,并直接调用map.iGrid.SetInventory()。
  2. Map类中创建一个新函数,例如map.SetInventoryAt(),然后调用iGrid.SetInventory()函数。
  3. 其他解决方案?
  4. 现在在我们的示例中,地图采用x和y坐标。然而,“网格”采用单个唯一的确定性索引来存储其信息。需要一个将coords转换为索引的函数。

    public int CoordsToIndex(int x, int y) {...}
    

    所有网格(InventoryGrid,TileGrid等等)都将使用此功能

    我的第二个问题是,根据最佳实践OO设计,该功能应该驻留在哪里?谁负责呢?

    1. 我是否制作了一个包含所有“网格”继承的函数的超类Grid以避免重复? C#specific:使用接口而不是超类?
    2. 我是否将它放在Map课程中,并认为“网格”不应该知道索引转换的坐标。这会影响第一个问题吗?
    3. 我是否创建了一个名为GridTools的独立(静态)类,其中包含帮助方法?
    4. 其他解决方案?

2 个答案:

答案 0 :(得分:0)

我会去a)#2和b)#1选择。

如果Map是Singleton,请将其设为静态。

a)#2因为getter暗示库存是一个成员,一个函数为你提供了更多的封装,并且在将来扩展对象模型时能够利用继承和接口。 Getter的单一值比嵌套类更好。 编辑:我看到您在#1中通过iGrid访问获取者,对于调用者来说,如何设置广告资源并不是很明显。 IMO,如果它被命名为InventoryGrid,那么使用暴露iGrid的getter也是同样可以接受的解决方案。如果您有子嵌套类,这将是一个更好的方法。

b)#1因为逻辑上避免在2个网格类需要相同方法的情况下重复,所以基础/超类是最好的方法之一。如果具有特定于实现的CoordsToIndex功能,您可以选择每个网格来实现接口,如果是这种情况,您也可以使用抽象基本方法。

  

所有网格(InventoryGrid,TileGrid等等)都将使用此功能

我认为虽然两个网格将共享完全相同的实现,但InventoryGrid和TileGrid的一个CoordsToIndex基类是您现在想要的(在您的设计中此时)。我假设CoordsToIndex依赖于两个网格中的数据,否则你想要解耦并将CoordsToIndex放在Map类中是一个好主意。

使用帮助程序类可以让它们更适合应用程序范围:配置,文件,加密,日志记录/跟踪,扩展方法等。

这两种方案的前2个选项都很好,因此您可以走上正轨。一条建议是接口允许您使用单元测试模拟,因此您可能需要编写一些单元测试来确认您可以测试您的oop架构。

答案 1 :(得分:0)

回答你的第一个问题,Google&#34;得墨忒耳法律&#34;。对于这类事情,这将为您提供良好的OOP指导。请记住,这是一个指导方针,而不是一个硬性规则。

要回答第二个问题,请将翻译代码放在Map类上,因为这是最简单的解决方案,您可以在以后轻松进行重构。如果您发现需要一堆相关的帮助程序,请创建一个新的Helpers类并将逻辑移到那里。如果您发现其他组件需要访问Maps,那么创建一个基本地图类并在那里移动逻辑。始终选择最基本的解决方案,因为当更好的解决方案变得更加清晰时,它是最容易改变的解决方案(Google YAGNI)。

话虽如此,考虑使用多维数组或锯齿状数组而不是字典。对我来说,他们更容易理解瓷砖地图,翻译问题就消失了。让问题消失比优雅解决问题更好。