Какой самый подходящий способ выставить списки внутри класса? - PullRequest
0 голосов
/ 12 января 2010

Представьте себе следующую модель:

  • A Таблица имеет много строк
  • A Ряд имеет много Ячейки

Каким будет предпочтительный интерфейс для работы с этими классами «объектно-ориентированным способом»?

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 ]

1 голос
/ 13 января 2010

Подумайте, сколько геттеров и сеттеров вы можете избавиться. В надежной ОО-структуре объекты экспортируют поведение друг другу, а не данные. Например, скелет модели геттера / сеттера человека:

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)

Я не скажу, что вам никогда не понадобятся геттеры в ОО-программе. Но я скажу так: сеттеры, в частности, должны заставить вас переосмыслить дизайн. И каждый раз, когда вы пишете либо получатель, либо установщик, пусть тихий голос в вашей голове спросит вас, есть ли способ заставить объекты экспортировать поведение, а не данные.

1 голос
/ 12 января 2010

Исходя из вашего комментария относительно использования: «Основным вариантом использования является добавление, сортировка и итерация значений», я бы, вероятно, не позволил бы извлекать отдельные элементы, а вместо этого попросил бы пользователя предоставить функтор для действия с сохраненным элементы. Выражается на С ++.

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

Вам придется адаптировать добавление / обновление / удаление вызовов в зависимости от того, как вы планируете вводить / обновлять данные. Этот дизайн сильно ориентирован на манипулирование коллекциями элементов. Положительным моментом этого дизайна является то, что вы не привязываете своего пользователя к конкретной базовой структуре того, как вы представляете таблицу. Это соответствует Закону Деметры.

Если вам нужен доступ к конкретным отдельным элементам, вам понадобится другой подход или сделать его расширением того, что уже было здесь предоставлено.

1 голос
/ 12 января 2010

Я думаю, что ответ в значительной степени субъективен. Если мы пойдем по вашему примеру, предоставление методов или свойств вашего класса для возврата значения по ссылке на строку / столбец может быть целесообразным. Они могут быть реализованы одновременно, например:

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

Вы также можете решить, что лучше выставить список напрямую, если «строки» данных конечны:

myClass.SomeArrayOfValues[itemIndex]

Я заметил, что вы используете фразы, такие как "таблицы" и "строки", поэтому я могу предположить, что вы хотите, чтобы ваш класс представлял базу данных или подобную структуру, но вы можете обнаружить, что, хотя это может быть эффективным для хранения данных таким способом Вы можете обнаружить, что предоставление данных в другой форме может иметь больше смысла для пользователя вашего класса.

В конце концов, то, как вы решите это сделать, должно быть действительно разработано с учетом цели самих данных и системы, которую вы моделируете, и это может быть решено только в каждом конкретном случае.

0 голосов
/ 12 января 2010

Многое зависит от данных и того, что вы планируете с ними делать. Потребуются ли пользователям отдельные ячейки? Отдельные строки / столбцы? Подразделы строк / столбцов?

Вероятно, самый чистый способ - предоставить функторные интерфейсы. Предоставьте одну или несколько функций, которые будут запускать функторы для каждого элемента или для подмножества, определенного в функторе.

Это может работать не так хорошо, если пользователям нужен доступ к сложным комбинациям ячеек.

0 голосов
/ 12 января 2010

Это зависит от того, как вы намереваетесь получить доступ к строкам / ячейкам.

Не существует единственно правильного способа сделать это - вам нужно решить, как вы хотите получить к ним доступ, и построить свои объекты так, чтобы они были доступны так, как вы хотите их использовать.

...