Допустим, мы делаем парсер. Одна реализация может быть:
public sealed class Parser1
{
public string Parse(string text)
{
...
}
}
Или мы могли бы вместо этого передать текст конструктору:
public sealed class Parser2
{
public Parser2(string text)
{
this.text = text;
}
public string Parse()
{
...
}
}
В обоих случаях использование простое, но что означает включение ввода параметров по Parser1
сравнению с другими? Какое сообщение я отправил коллегам-программистам, когда они смотрят на API? Кроме того, есть ли технические преимущества / недостатки в определенных случаях?
Другой вопрос возникает, когда я понимаю, что интерфейс был бы совершенно бессмысленным во второй реализации:
public interface IParser
{
string Parse();
}
... где интерфейс первого может служить хотя бы какой-то цели. Означает ли это что-то конкретное, что класс является «интерфейсом» или нет?
object-oriented
interfaces
methods
construction
ciscoheat
источник
источник
Ответы:
Семантически говоря, в ООП вы должны передавать конструктору только набор параметров, которые необходимы для построения класса - аналогично, когда вы вызываете метод, вы должны только передавать ему параметры, необходимые для выполнения его бизнес-логики.
Параметры, которые вам нужно передать в конструкторе, это параметры, которые не имеют разумного значения по умолчанию, и если ваш класс является неизменным (или действительно
struct
), то должны передаваться все свойства, отличные от стандартных.Относительно ваших двух примеров:
text
к конструктору, он намекает на то, чтоParser2
класс будет специально создан для последующего анализа этого экземпляра текста. Это будет конкретный парсер. Это обычно имеет место, когда создание класса очень дорого или тонко, RegEx может быть скомпилирован в конструкторе, поэтому, как только вы держите экземпляр, вы можете использовать его повторно, не оплачивая стоимость компиляции; Другой пример - инициализация PRNG - лучше, если это делается редко.text
к методу, он сигнализирует, чтоParser1
его можно использовать повторно для анализа различных текстов по вызовам.источник
Хорошо, давайте вспомним, что значит передавать переменную как параметр конструктора: Вы инициализируете объект, чтобы использовать его переменные экземпляра в методах объекта. Дело в том, что вы, вероятно, хотите использовать его более чем в одном методе, так как вы хотите иметь высокую степень сплоченности в своем классе.
Передача параметра непосредственно методу означает, что отправка сообщения объекту и, возможно, получение ответа. Таким образом, клиент хочет, чтобы объект предоставил ему услугу.
Итак, в заключение, это два совершенно разных способа передачи параметров, и вы должны выбрать, должен ли ваш объект либо предоставлять услугу, либо предоставлять некоторые функциональные возможности по своей сути, одновременно управляя некоторой информацией.
источник
Это фундаментальное изменение дизайна. И дизайн должен передавать намерение и смысл. Вам нужно иметь отдельные объекты для каждой строки, которую вы хотите проанализировать? Другими словами, зачем нам нужен экземпляр синтаксического анализатора со строкой X и другой экземпляр со строкой Y? Что такое синтаксический анализ (ing) и заданная строка, что оба должны жить и умирать вместе? Предполагая, что «базовая [синтаксический анализ] реализация» (как говорит Роберт Харви) не меняется, похоже, в этом нет никакого смысла. И даже тогда его сомнительное ИМХО.
Параметры конструктора говорят мне, что эти вещи необходимы для объекта. Правильное состояние не гарантируется без них. Также я знаю, как / почему один парсер принципиально отличается от другого.
Параметры конструктора не дают мне знать слишком много о том, как использовать класс. Если вместо этого я должен установить определенные свойства - откуда мне это знать? Целая банка червей открывается. Какие свойства? В каком порядке? Прежде чем использовать какие методы? и так далее.
Интерфейс, как и в API, - это методы и свойства, предоставляемые клиентскому коду. Не зацикливайтесь
public interface { ... }
исключительно. Таким образом, значение интерфейса заключается в дилемме параметра «либо», либо «конструктор против метода», а неpublic interface Iparser
противpublic sealed class Parser
sealed
Класс нечетный. Если я думаю о различных реализациях парсера - вы упомянули «Iparser» - тогда наследование - моя первая мысль. Это просто естественное концептуальное расширение моего мышления. То есть всеParserX
s в основномParser
s. Как еще это сказать? ... Немецкая Шепард - это собака (наследство), но я могу научить своего попугая лаять (вести себя как собака - "интерфейс"); но Полли не собака, просто притворяется, выучив подмножество упрямства Классы, абстрактные или иные, прекрасно работают как интерфейсы .источник
Вторая версия класса может быть сделана неизменной.
Интерфейс все еще можно использовать для предоставления возможности замены базовой реализации.
источник
Parser1
Сборка с конструктором по умолчанию и передача входного текста в метод подразумевает, что Parser1 можно использовать повторно.
Parser2
Передача входного текста в конструктор подразумевает, что новый Parser2 должен быть создан для каждой входной строки.
источник