0

想象以下模型:

  • 一个有很多
  • A Row有许多单元格

以“面向对象的方式”处理这些类的更好接口是什么?

1 - 提供对属性/单元格的访问(不一定公开底层数据结构,但创建例如类 RowCollection...)

my_table = new Table()
my_table.rows.add([1,2,3])
my_row = my_table.rows.get(0)
my_row.cells.get(0)
for(cell in my_row.cells) {}
...

2 - 或者直接在TableRow类中提供方法

my_table = new Table()
my_table.add_row([1,2,3])
my_row = my_table.get_row(0)
my_row.get_cell(0)
for(cell in my_row.get_cells) {}
...

3 - 以上都不是...

4

5 回答 5

1

我认为答案在很大程度上是主观的。如果我们以您的示例为例,提供类的方法或属性以通过行/列引用返回值可能是合适的。这些可以同时实现,例如:

myClass.Row[x].Column[y]    
myClass.Column[y].Row[x]    
myClass.Cell[x,y]

如果数据“行”是有限的,您可能还决定直接公开列表更好:

myClass.SomeArrayOfValues[itemIndex]

我注意到您使用诸如“表”和“行”之类的短语,因此我可能假设您希望您的类表示数据库或类似结构,但您可能会发现虽然以这种方式存储数据可能很有效,但您可能发现以另一种形式公开数据可能对您班级的用户更有意义。

最后,您选择如何执行此操作应该真正设计为反映数据本身和您正在建模的系统的目的,并且只能根据具体情况决定。

于 2010-01-12T12:12:58.970 回答
1

考虑一下您可以摆脱多少个 getter 和 setter。一个健壮的 OO 设计具有相互导出行为的对象,而不是数据。例如,Person 的 getter/setter 模型的骨架:

class Person:
  def set_name(value):
  def get_name:
  def set_age(value):
  def get_age:
  def set_drink(value):
  def get_drink:
  def set_favorite_drink(value):
  def get_favorite_drink:

下面是一些使用 Person 的(伪)代码:

def order_drink(person)
  if person.age >= 21:
    puts "#{person.name} can have a drink"
    person.drink = bar.order(person.favorite_drink)
  else:
    puts "#{person.name} cannot drink (legally)."

以下是您如何让一个没有 getter 或 setter 的人参与点酒:

class Person:
  def order_drink_from(bar):
    if self.age >= 21:
      puts "#{self.name} can have a drink"
      self.drink = bar.order(favorite_drink)
    else:
      puts "#{self.name} cannot drink (legally)"

像这样使用:

person.order_drink_from(bar)

我不会说在 OO 程序中永远不需要 getter。但我要说的是:尤其是二传手,应该让你重新思考设计。每次编写 getter 或 setter 时,脑后都会有一个小声音询问您是否有办法让对象导出行为而不是数据。

于 2010-01-13T02:16:19.167 回答
1

根据您对用法的评论,“主要用例是添加、排序和迭代值”,我可能不允许检索单个元素,而是让用户提供一个仿函数来对存储的元素进行操作。用 C++ 表示。

class Table
{
public:
    Table();
    //Table(unsigned int numberOfRows, unsigned int numberOfCells);

    void addRow();
    void addCell();

    //Throw exception if out of range or don't supply these functions if not needed by user.
    void removeRow(unsigned int rowNumber);
    void removeCell(unsigned int rowNumber, unsigned int cellNumber);

    //Iterate over entire table
    template<class Pred>
    void forEach(Pred pred);

    //Iterate over a specific row, throw exception if row is out of range.
    template<class Pred>
    void forEach(unsigned int row, Pred pred);
}

您必须根据您计划输入/更新数据的方式来定制添加/更新/删除调用。这种设计强烈倾向于操纵元素的集合。这种设计的好处是你没有让你的用户接受你如何表示表格的特定底层结构。这符合得墨忒耳法则。

如果您需要访问特定的单个元素,您将需要一种不同的方法或使其成为此处已提供内容的扩展。

于 2010-01-12T14:33:42.903 回答
0

这取决于您打算如何访问行/单元格。

没有一种正确的方法 - 您需要决定如何访问它们并构建您的对象以以您想要使用它们的方式公开它们。

于 2010-01-12T11:27:08.920 回答
0

这在很大程度上取决于数据以及您打算用它做什么。用户会想要单个单元格吗?单独的行/列?行/列的子部分?

可能最简洁的方法是提供函子接口。提供一个或多个函数,这些函数将在每个元素上运行仿函数,或者在仿函数中定义的子集上运行仿函数。

如果用户需要访问复杂的单元格组合,这可能效果不佳。

于 2010-01-12T11:28:22.923 回答