2010-01-12 4 views
0

Представьте себе следующую модель:Каков наиболее подходящий способ публикации списков внутри класса?

  • Таблица имеет много Ряды
  • Ряд имеет много Cells

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

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 - или предоставить методы непосредственно в таблице и Row классы

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 - Ничего из перечисленного ...

+0

Основным вариантом использования является добавление, сортировка и итерирование значений –

ответ

0

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

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

0

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

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

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

1

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

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

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

myClass.SomeArrayOfValues[itemIndex] 

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

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

+0

Цель состоит в том, чтобы представить основную структуру электронных таблиц. –

+1

Если это имеет смысл для вас, вы можете даже разоблачить метод или свойство, которое использует строку из вашего приложения, которая использует стандартную нотацию ячейки электронной таблицы (например: «A1», «D3» и т. д.). Вероятно, это было бы лучше всего как расширение или обертка для чего-то в соответствии с примерами, которые я привел в моем ответе выше. –

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

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

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

1

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

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: 

А вот некоторые (псевдо-) код, который использует лицо:

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. Но я скажу это: сеттеры, особенно, должны заставить вас переосмыслить дизайн. И каждый раз, когда вы пишете либо геттер, либо сеттер, пусть немного голос в затылке спросит вас, есть ли способ экспортировать объекты, а не данные.