Принимаете ли вы интерфейсы в качестве параметров конструктора?
Применима ли рекомендацияКшиштофа к конструкторам? Если да, то как вы его правильно реализуете?
Мы рекомендуем использовать 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 ответов:
Вы должны избегать понижающей передачи; в вашем примере я бы предложил, чтобы тип вашего параметра contructor соответствовал (должен быть таким же) типу ваших данных-членов (т. е. либо
Collection<String>
илиIEnumerable<String>
).Или есть решение Марка, которое отличается: потому что решение Марка означает, что ваши данные-члены не только другой тип, но и другой экземпляр (т. е. если вы изменяете данные-члены, то вы изменяете копию исходной коллекции, а не редактирование самой исходной коллекции; аналогично, если исходная коллекция изменяется после создания копии, ваши локальные данные копии / члена не включают это последующее изменение в исходную коллекцию).
Вы не должны использовать версию
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);
Я считаю, что по возможности следует избегать нисходящего вещания. Если класс хранит вход в виде конкретного класса " Collection "(что означает, что этот класс работает с" Collection", то я думаю, что более естественно просто принять вход типа" Collection " вместо аналога интерфейса.
Это перекладывает ответственность за понижающую передачу (если это необходимо) обратно на потребителя, который должен знать, что он делает, если он действительно понижает ее.
С другой стороны, я бы сказал, что принятие ввода в качестве интерфейса лучше, чем конкретного класса, поскольку это позволяет гибкость подачи в макет объектов легче. Однако для этого потребуется, чтобы внутренние элементы класса зависели от интерфейса, а не от конкретного класса (таким образом, в примере переменная-член будет иметь значение IEnumerable вместо Collection).
Я согласен с яписканом, что решение марка фактически изменило использование, создав копию входных данных, и, таким образом, произошло изменение ответственности:
Before: входные данные всегда разделяются между потребителем и этим классом. Таким образом, изменение входных данных является "общим" между потребителем и этим классом
After: понимание этого класса входных данных отделяется от потребителя после вызова конструктора.
Если то, что вы храните, является коллекцией, поэтому я предпочитаю получать ICollection в качестве входных данных.
Почему бы не принять параметр типа
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; } }
Я бы согласился с Пейдж, в некотором роде.
Я согласен, что вы должны передать IEnumerable в качестве входных данных (таким образом, вы поддерживаете любую перечисляемую коллекцию).
Но то, что вы делаете выше со свойством StringCollection, для меня не имеет смысла - вы понижаете передачу, которая не будет работать.
- Matt
Это, вероятно, все о том, чтобы не раскрывать слишком много вашей реализации. В идеале, если вы разрабатываете публичный API, вы должны предоставить только самый минимум своей реализации. Если вы вернете интерфейс полного списка, у пользователя публичного API будет множество способов испортить внутренности ваших классов способами, которые вы, возможно, не планировали.
- - - - edit - - - -