Принимаете ли вы интерфейсы в качестве параметров конструктора? - PullRequest
2 голосов
/ 09 января 2009

Применима ли рекомендация Кшиштофа к конструкторам? Если да, то как ты правильно это делаешь?

Мы рекомендуем использовать Collection, ReadOnlyCollection или KeyedCollection для выходных данных и свойств и интерфейсов IEnumerable, ICollection, IList для входных данных.

Например,

public ClassA
{
    private Collection<String> strings;
    public Collection<String> Strings { get { return strings; } }
    public ClassA(IEnumerable<String> strings)
    {
        this.strings = strings; // this does not compile
        this.strings = strings as Collection<String>; // compiles (and usually runs?)
    }
}

Ответы [ 7 ]

5 голосов
/ 09 января 2009

Вам следует избегать удушения; в вашем примере я бы предположил, что тип вашего параметра contructor должен соответствовать (должен совпадать с) типом данных вашего члена (т.е. либо Collection<String> или IEnumerable<String>).

Или есть решение Марка, которое отличается: потому что решение Марка означает, что ваши данные участника не только другого типа, но и другого экземпляра (то есть, если вы изменяете данные участника, то вы модифицируете копию исходная коллекция, не редактируя саму оригинальную коллекцию; аналогично, если исходная коллекция была изменена после того, как вы сделали копию, ваши локальные данные копии / члена не включают это последующее изменение в исходную коллекцию).

4 голосов
/ 09 января 2009

Вы не должны использовать версию as - вы должны либо принять и сохранить что-то повторяемое, например IList<T>, либо создать новую локальную коллекцию данных:

this.strings = new Collection<string>();
foreach(string s in strings) { this.strings.Add(s); }

На самом деле, я бы сам использовал List<T>; тогда вы можете сделать (хотя это не причина для использования List<T>):

this.strings = new List<string>(strings);
1 голос
/ 12 января 2009

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

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

С другой стороны, я бы сказал, что принимать входные данные в качестве интерфейса лучше, чем конкретный класс, поскольку он позволяет более гибко вводить фиктивные объекты. Однако для этого потребуется, чтобы внутреннее содержимое класса зависело от интерфейса, а не от конкретного класса (таким образом, в примере переменная-член будет иметь IEnumerable вместо Collection).

Я согласен с yapiskan, что решение Марка фактически изменило использование, создав копию ввода, и, таким образом, произошла смена ответственности:

До: входные данные все время распределяются между потребителем и этим классом. Таким образом, изменение ввода является «общим» для потребителя и этого класса

После: понимание этого класса входных данных отсоединяется от потребителя после вызова конструктора.

0 голосов
/ 09 января 2009

Я бы согласился с Пейдж, вроде как.

Я согласен, что вы должны передавать IEnumerable в качестве входных данных (таким образом, вы поддерживаете любую перечислимую коллекцию).

Но то, что вы делаете выше со свойством StringCollection, не имеет смысла для меня - вы удручаете, что не сработает.

Матф

0 голосов
/ 09 января 2009

Почему бы не принять параметр типа IEnumerable<String> и привести его к извлечению?

public ClassA
{
    private IEnumberable<String> strings;

    public Collection<String> StringCollection {
        get { return (Collection<String>) strings; }
    }

    public ClassA(IEnumerable<String> strings)
    {
        this.strings = strings; 
    }
}
0 голосов
/ 09 января 2009

Это, вероятно, все о том, чтобы не показывать слишком много вашей реализации. В идеале, если вы разрабатываете общедоступный API, вы должны раскрыть только минимум вашей реализации. Если вы вернете полный интерфейс List, у пользователя общедоступного API будет множество способов связываться с внутренностями ваших классов способами, которые вы, возможно, не предполагали.

---- редактировать ----

0 голосов
/ 09 января 2009

Если вы храните коллекцию, я предпочитаю получать ICollection в качестве входных данных.

...