在类中公开列表最合适的方法是什么?

时间:2010-01-12 11:21:36

标签: language-agnostic oop encapsulation information-hiding

想象一下以下模型:

  • 有多个
  • 有多个单元格

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

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 - 或直接在类中提供方法

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 - 以上都不是......

5 个答案:

答案 0 :(得分:1)

我认为答案主要是主观的。如果我们按照您的示例进行操作,则提供类的方法或属性以通过行/列引用返回值可能是合适的。这些可以同时实施,例如:

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

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

myClass.SomeArrayOfValues[itemIndex]

我注意到你使用了像“tables”和“rows”这样的短语,所以我可能会假设你希望你的类代表一个数据库或类似的结构,但你可能会发现虽然以这种方式存储数据可能是有效的,您可能会发现以另一种形式公开数据可能对您的班级用户更有意义。

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

答案 1 :(得分: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);
}

您必须根据计划输入/更新数据的方式来定制添加/更新/删除调用。这种设计强烈倾向于操纵元素集合。这种设计的好处在于,您不会将用户提交给表示表的特定底层结构。这符合得墨忒耳法则。

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

答案 2 :(得分:1)

考虑一下你可以摆脱多少吸气剂和二传手。强大的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)."

以下是如何让一个人在订购饮料时没有任何吸气者或制定者:

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时,在你脑后留下一个小小的声音,问你是否有办法让对象导出行为而不是数据。

答案 3 :(得分:0)

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

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

答案 4 :(得分:0)

这很大程度上取决于数据以及您打算如何处理它。 用户是否需要单个细胞?个别行/列?行/列的小节?

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

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