Дизайн OO - Вы используете общественные собственности или частные поля внутренне? [дубликат]

Очень эффективный алгоритм, адаптированный из книги Йорга Арндта «Вычислительные вопросы»
(Глава 7.2 Co-lexicographic order for compositions into exactly k parts)

n = 4
k = 3

x = [0] * n
x[0] = k

while True:
    print(x)
    v = x[-1]
    if (k==v ):
        break
    x[-1] = 0
    j = -2
    while (0==x[j]):
        j -= 1
    x[j] -= 1
    x[j+1] = 1 + v

[3, 0, 0, 0]
[2, 1, 0, 0]
[2, 0, 1, 0]
[2, 0, 0, 1]
[1, 2, 0, 0]
[1, 1, 1, 0]
[1, 1, 0, 1]
[1, 0, 2, 0]
[1, 0, 1, 1]
[1, 0, 0, 2]
[0, 3, 0, 0]
[0, 2, 1, 0]
[0, 2, 0, 1]
[0, 1, 2, 0]
[0, 1, 1, 1]
[0, 1, 0, 2]
[0, 0, 3, 0]
[0, 0, 2, 1]
[0, 0, 1, 2]
[0, 0, 0, 3]

Количество композиций и время в секундах для простого Python (возможно, массивы с нулевыми значениями) быстрее) для n = 100, и k = 2,3,4,5 (2,8 ГГц Cel-1840)

2  5050 0.040000200271606445
3  171700 0.9900014400482178
4  4421275 20.02204465866089
5  91962520 372.03577995300293
I expect time  2 hours for 100/6 generation

То же самое с массивами numpy (x = np.zeros((n,), dtype=int)) дает хуже [1116 ] результаты - но, возможно, потому что я не знаю, как их правильно использовать

2  5050 0.07999992370605469
3  171700 2.390003204345703
4  4421275 54.74532389640808

Собственный код (это Delphi, компиляторы C / C ++ могли бы оптимизировать лучше) генерирует 100/6 за 21 секунду

3  171700  0.012
4  4421275  0.125
5  91962520  1.544
6  1609344100 20.748

Невозможно заснуть, пока не будут выполнены все измерения:)

MSVS VC ++: 18 секунд ! (Оптимизация O2)

5  91962520 1.466
6  1609344100 18.283

Итак, 100 миллионов вариантов в секунду. Много времени тратится на проверку пустых ячеек (потому что коэффициент заполнения мал). Скорость, описанная Арндтом, достигается при более высоких коэффициентах k / n и составляет около 300-500 миллионов вариантов в секунду:

n=25, k=15 25140840660 60.981  400 millions per second
6
задан Joren 25 September 2009 в 16:35
поделиться

10 ответов

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

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

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

Но в целом, я бы сказал, доступ через свойство.

РЕДАКТИРОВАТЬ

Пример (тривиальный / надуманный)

public class Person
{
    private string _name = "";
    private List<String> oldnames = new ArrayList();

    public string Name
    {
        get { return _name; }
        set 
        {
           oldnames.Add(_name);
           _name = value; 
        }
    }

    public Person(string name)
    {
        _name = name; //should I use the property or field here?
    }
}

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

14
ответ дан 8 December 2019 в 05:57
поделиться

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

2
ответ дан 8 December 2019 в 05:57
поделиться

По большей части это похоже на предпочтение кода, но я предпочитаю использовать публичные или когда-либо частные свойства, вы можете просто добавить некоторая логика для свойства без каких-либо изменений в коде вызывающего. Также в 3.5 .NET у вас есть полезный код сахара как autoproperty.

2
ответ дан 8 December 2019 в 05:57
поделиться

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

public class MyClass
{
    private string _MyProperty;

    public MyProperty { get { return _MyProperty; } }

    public MyClass ()
    {
        _MyProperty = SomeVeryComplexPropertyInitializationLogic ();
    }
}
1
ответ дан 8 December 2019 в 05:57
поделиться

Обычно я использую общедоступные свойства с некоторыми исключениями, где я могу захотеть избежать любого дополнительного кода, написанного в методе доступа к свойствам. Благодаря автоматическим свойствам в C # 3.0 я редко создаю вспомогательные поля вручную; как правило, только когда значение по умолчанию для поля автоматического резервного копирования не подходит для моего свойства.

0
ответ дан 8 December 2019 в 05:57
поделиться

Если вы используете имя поля, вы не получите инкапсуляцию. Инкапсуляция применяется не только между классами, но и внутри класса.

Если в какой-то момент в будущем вы переопределите поле, но оставите подписи функции доступа / установщика такими же, не только внешние классы, которые используют ваш класс, не сломаются, но Внутренние процедуры в вашем собственном классе тоже не сломаются.

Возьмем, к примеру, этот код, свободно основанный на коде, который отображается в платформе Apache Wicket (хотя эта среда не страдает этой проблемой; я просто использую ее для иллюстрации):

Допустим, это был оригинальный учебный класс:

class RadioChoice {
  private String prefix;

  RadioChoice( String prefix ) {
    this.prefix = prefix ;

  setPrefix( String prefix )  {
    this.prefix = prefix ;
   }
}

Здесь мы уже видим проблему: та же самая операция this.prefix = prefix происходит в местах буксировки. Он предназначен для того, чтобы делать одно и то же, но поскольку это происходит в двух местах, это «одно и то же» может расходиться в две разные вещи. (Сравните это с нормализацией базы данных, практикой, предназначенной для предотвращения именно этого.)

Теперь у Apache Wicket есть концепция записи изменений в том, как он отображает веб-страницы, так что эти изменения могут быть отменены. Это делается путем сохранения списка «отмененных» объектов. Префикс RadioChoice - это одна из тех вещей, которые можно отменить, и поэтому установщик 'prefix' должен записать изменение:

class RadioChoice {
  private String prefix;

  RadioChoice( String prefix ) {
    this.prefix = prefix ;

  setPrefix( String prefix )  {
    // save the old prefix
    this.getPage().addChange( new PrefixChange( this.prefix ) );
    // set the new one
    this.prefix = prefix ;
   }
}

Теперь посмотрим, что произойдет: поскольку конструктор устанавливает префикс напрямую, ctor не сохраняет никаких изменений. Если бы мы использовали установщик, ctor бы автоматически " В целом, использование сеттеров и геттеров защищает вас от изменений.

2
ответ дан 8 December 2019 в 05:57
поделиться

Использовать недвижимость. Или еще лучше, если вы используете C # 3.0 или выше, используйте автоматические свойства, например, так:

public class Person
{
    public string Name { get; set; }

    public Person(string name)
    {
        Name = name; //should I use the property or field here?
    }
}

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

1
ответ дан 8 December 2019 в 05:57
поделиться

Вы должны использовать «Имя» (свойство), потому что, если вы хотите проверить это значение, вы можете поместить его в установщик свойства «Name», а затем будет использоваться как для конструктора, так и для последующего задания значения.

0
ответ дан 8 December 2019 в 05:57
поделиться

По крайней мере в Java нет НИКАКОГО способа использовать открытые поля, потому что старые добрые соглашения javabeans, которые кажутся всем использовать. Я думаю, что C # имеет свойства в качестве конструкций первого языка. Я бы пошел на это

0
ответ дан 8 December 2019 в 05:57
поделиться

Это зависит. Иногда вы будете писать геттеры / сеттеры, которые выполняют важную предварительную обработку для любого реалистичного взаимодействия с полем. Например, если строковое поле имеет ограничение на то, что оно всегда должно быть в нижнем регистре, то по крайней мере один из ваших методов getter / setter должен вызвать .ToLower () или .ToLowerInvariant (), и в коде вашего класса вы, вероятно, Я хочу использовать это, чтобы убедиться, что ограничение применено.

Однако, также будут времена, когда вам нужно будет обойти эту логику предварительной обработки. Фактически, я видел случаи, когда разработчики непреднамеренно создавали бесконечные циклы, используя открытое свойство, а не приватное поле (извините, я не могу вспомнить пример из головы).

Классы, сгенерированные Linq To SQL, хороший пример, я думаю, потому что они показывают, сколько логики может существовать в свойстве. Попробуйте написать несколько методов расширения, и вы начнете понимать разницу.

Я думаю, суть в том, что это зависит от того, какую логику вы используете в любой заданной точке класса, и какая предварительная обработка существует в методах получения / установки. Если вы когда-либо не уверены или вам кажется, что это не имеет значения, вероятно, лучше использовать свойство getters / setters / public, чтобы вы могли написать более понятный код, который будет следовать ограничениям, добавленным позже.

0
ответ дан 8 December 2019 в 05:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: