Допустим, по какой-то причине все объекты созданы таким образом: $ obj = CLASS :: getInstance (). Затем мы внедряем зависимости с помощью сеттеров и выполняем начальную инициализацию с помощью $ obj-> initInstance (); Есть ли реальные проблемы или ситуации, которые нельзя решить, если мы вообще не будем использовать конструкторы?
Причиной создания объекта таким образом является то, что мы можем заменить класс внутри getInstance () в соответствии с некоторыми правилами.
Я работаю в PHP, если это имеет значение
object-oriented-design
class-design
Аксель Фоли
источник
источник
Ответы:
Я бы сказал, что это сильно мешает вашему дизайнерскому пространству.
Конструкторы - отличное место для инициализации и проверки переданных параметров. Если вы больше не можете использовать их для этого, то инициализация, обработка состояний (или простое конструирование запрещенных объектов «сломанных» объектов) становится намного сложнее и частично невозможным.
Например, если каждый
Foo
объект нуждается в a,Frobnicator
он может проверить в своем конструкторе, еслиFrobnicator
он не равен NULL. Если вы уберете конструктор, его будет сложнее проверить. Вы проверяете в каждой точке, где это будет использоваться? Вinit()
методе (эффективно экстернализуя метод конструктора)? Никогда не проверяй и надейся на лучшее?Хотя вы, вероятно, все еще могли бы реализовать все (в конце концов, вы все еще пытаетесь завершить), некоторые вещи сделать будет намного сложнее.
Лично я бы посоветовал изучить инъекцию зависимости / инверсию контроля . Эти методы также позволяют переключать конкретные классы реализации, но они не мешают написанию / использованию конструкторов.
источник
HttpClient
тогда он проверяет, является ли этот параметр ненулевым). И если эти ограничения не выполняются, то может возникнуть исключение. Это не совсем возможно с подходом конструкции и набора значений.init()
, что вполне возможно, хотя это просто налагает больше бремени обслуживания.2 преимущества для конструкторов:
Конструкторы допускают атомарные этапы построения объекта.
Я мог бы избежать конструктора и использовать сеттеры для всего, но как насчет обязательных свойств, как предложил Йоахим Зауэр? С помощью конструктора объект владеет собственной логикой конструирования, чтобы гарантировать отсутствие недопустимых экземпляров такого класса .
Если для создания экземпляра
Foo
требуется установить 3 свойства, конструктор может взять ссылку на все 3, проверить их и выдать исключение, если они недействительны.Инкапсуляция
Полагаясь исключительно на сеттеры, бремя объекта возлагается на потребителя объекта. Могут быть разные комбинации свойств, которые являются действительными.
Например, каждому
Foo
экземпляру требуется либо экземплярBar
свойства,bar
либо экземплярBarFinder
свойстваbarFinder
. Он может использовать любой из них. Вы можете создать конструктор для каждого допустимого набора параметров и таким образом применять соглашения.Логика и семантика для объектов живут внутри самого объекта. Это хорошая инкапсуляция.
источник
Да, вы можете жить без конструкторов.
Конечно, у вас может получиться много дублированного кода котельной плиты. И если ваше приложение имеет какой-либо масштаб, вы, вероятно, потратите много времени, пытаясь найти источник проблемы, когда этот стандартный код не используется последовательно во всем приложении.
Но нет, вам не нужны ваши собственные конструкторы. Конечно, вам не нужны «классы» и объекты.
Теперь, если ваша цель состоит в том, чтобы использовать какой-то фабричный шаблон для создания объекта, это не является взаимоисключающим использованием конструкторов при инициализации ваших объектов.
источник
Преимущество использования конструкторов состоит в том, что они упрощают гарантию того, что у вас никогда не будет недопустимого объекта.
Конструктор дает вам возможность установить все переменные-члены объекта в допустимое состояние. Затем, когда вы убедитесь, что никакой метод мутатора не может изменить объект на недопустимое состояние, у вас никогда не будет недопустимого объекта, что избавит вас от множества ошибок.
Но когда новый объект создается в недопустимом состоянии, и вы должны вызвать некоторые установщики, чтобы перевести его в допустимое состояние, в котором он может использоваться, вы рискуете, что потребитель класса забудет вызвать эти установщики или вызовет их неправильно и вы в конечном итоге с недопустимым объектом.
Обходным путем может быть создание объектов только с помощью фабричного метода, который проверяет достоверность каждого создаваемого объекта, прежде чем возвращать его вызывающей стороне.
источник
Я думаю, ты делаешь это сложнее, чем нужно. Мы можем просто вставлять зависимости через конструктор - и если у вас их много, просто используйте словарную структуру, чтобы вы могли указать, какие из них вы хотите использовать:
А внутри конструктора вы можете обеспечить согласованность следующим образом:
$args
затем можно использовать для установки закрытых членов по мере необходимости.Когда все сделано полностью в конструкторе, то так никогда не будет промежуточного состояния, где
$obj
существует, но не инициализируется, как было бы в системе, описанной в вопросе. Лучше избегать таких промежуточных состояний, потому что вы не можете гарантировать, что объект всегда будет использоваться правильно.источник
Я на самом деле думал о похожих вещах.
Я задал вопрос: «Что делает конструктор, и возможно ли сделать это по-другому?» Я пришел к таким выводам:
Это обеспечивает инициализацию некоторых свойств. Принимая их в качестве параметров и устанавливая их. Но это может быть легко осуществлено компилятором. Просто аннотируя поля или свойства как «обязательные», компилятор проверяет во время создания экземпляра, правильно ли все установлено. Вызов для создания экземпляра, вероятно, будет таким же, просто не будет никакого метода конструктора.
Гарантирует, что свойства действительны. Это может быть легко достигнуто утверждением условия. Опять же, вы просто аннотируете свойства с правильными условиями. Некоторые языки уже делают это.
Некоторая более сложная логика построения. Современные шаблоны не рекомендуют делать это в конструкторе, но предлагают использовать специализированные фабричные методы или классы. Так что использование конструкторов в этом случае минимально.
Итак, чтобы ответить на ваш вопрос: да, я считаю, что это возможно. Но это потребовало бы больших изменений в дизайне языка.
И я только заметил, что мой ответ довольно ОТ.
источник
Да, вы можете делать практически все без использования конструкторов, но это явно расточает преимущества языков объектно-ориентированного программирования.
В современных языках (я буду говорить здесь о C #, на котором я программирую) вы можете ограничить части кода, которые могут быть запущены только в конструкторе. Благодаря которому вы можете избежать неуклюжих ошибок. Одной из таких вещей является модификатор readonly :
Как ранее рекомендовал Йоахим Зауэр, вместо того, чтобы использовать
Factory
дизайн-паттер, прочтите оDependency Injection
. Я бы порекомендовал почитать Dependency Injection в .NET Марка Симанна .источник
Создавать объект с типом в зависимости от требований это абсолютно возможно. Это может быть сам объект, использующий глобальные переменные системы для возврата определенного типа.
Тем не менее, иметь класс в коде, который может быть «Все», это понятие динамического типа . Я лично считаю, что такой подход создает несогласованность в вашем коде, создает тестовые комплексы *, и «будущее становится неопределенным» в отношении потока предлагаемой работы.
* Я имею в виду тот факт, что тесты должны учитывать сначала тип, а затем результат, которого вы хотите достичь. Затем вы создаете большой вложенный тест.
источник
Чтобы сбалансировать некоторые другие ответы, утверждая:
а также
Такие заявления иногда предполагают, что:
Но это не совсем так. Большинство языков не имеют правила против передачи конструктора
this
(self
или любого языка, который его называет) внешнему коду. Такой конструктор полностью подчиняется правилу, указанному выше, и все же он рискует подвергнуть полу-построенные объекты внешнему коду. Это незначительный момент, но легко упускается из виду.источник
Это несколько анекдотично, но я обычно резервирую конструкторы для состояния, необходимого для того, чтобы объект был полным и пригодным для использования. Запрет на любое установочное внедрение, после запуска конструктора мой объект сможет выполнять необходимые для него задачи.
Все, что можно отложить, я оставляю вне конструктора (подготовка выходных значений и т. Д.). При таком подходе я чувствую, что не использую конструкторы ни для чего, но внедрение зависимостей имеет смысл.
Это также имеет дополнительное преимущество, заключающееся в том, что ваш процесс умственного проектирования не требует преждевременных действий. Вы не будете инициализировать или выполнять логику, которая, возможно, никогда не будет использована, потому что в лучшем случае все, что вы делаете, - это базовые настройки для предстоящей работы.
источник