Я кодирую уже около 3-х лет. Вторая половина это как профессиональный разработчик. У меня была сильная привязанность к Java еще в тот день, когда я начал писать код. Позже я перешел на PHP, в частности на фреймворк Laravel, и теперь я полный рабочий день PHP-разработчик, разрабатывающий приложения с использованием фреймворка Laravel. Несмотря на то, что я изменил язык программирования с Java на PHP, я всегда кодировал в объектно-ориентированной среде.

Работать в Laravel - это весело. Его кодовая база настолько выразительна и красива для чтения. Если вы погрузитесь в суть Laravel, вы обнаружите, что он использует множество шаблонов объектно-ориентированного дизайна, и это побуждает меня создавать проект, над которым я работаю, с мышлением объектно-ориентированного подхода. Но что такое объектно-ориентированный подход? Следование принципам SOLID, реализация шаблонов проектирования там, где это применимо, предпочтение композиции перед наследованием, максимальное написание СУХОГО кода и т. Д. - вот некоторые из признаков следования объектно-ориентированному подходу. Но даже следуя шаблонам и принципам, я часто получал запутанные классы, которые было очень трудно понять и поддерживать.

Как правило, я разрабатывал классы на основе ответственности, а затем использовал композицию, чтобы соединить их вместе. Но даже в этом случае у меня остались классы, подобные приведенным ниже:

<?php
class Invoice
{
    public function __construct(
        InvoiceRepositoryInterface $invoice,
        InvoiceItemRepositoryInterface $invoiceItem,
        DiscountRepositoryInterface $discount,
        Payment $payment,
        DatabaseManager $database,
        MessengerInterface $messenger,
        InvoiceEmailInterface $invoiceEmail,
        ConverterInterface $converter,
        TenantFileManager $tenantFileManager,
        Dispatcher $event,
        LoggerInterface $logger
    )
...

Несмотря на то, что я убедил себя, что все это сделал для рефакторинга класса Invoice, он превратился в класс GOD с более чем 1000 строк кода. Основная проблема с этим дизайном заключалась в том, что даже для вызова метода во внедренных классах мне приходилось создавать прокси-метод в классе Invoice.

Я спросил себя: «Что я сделал не так?».

Недавно Laracasts выпустили серию под названием Взбейте чудовищный код в форму. Это пролило свет на конкретные проблемы, с которыми я столкнулся. Я понял, что проблема не в разделении задач, а в том, как я собрал классы вместе. Не все нужно вводить через конструктор. Не все нужно извлекать из класса. Есть более эффективные методы для извлечения общей логики из класса и возможности использовать ее в этом классе. Проходя серию статей, я узнал несколько новых способов объединения функциональных возможностей без необходимости вводить классы в конструктор или создавать класс в первую очередь. Я перечислил некоторые из методов ниже.

  1. Используйте черты характера
<?php


class ExtraMappings
{
    use MapsExtraMappings, ModifiesEMISCode,       
        ExtractsFoundationAndRoof, ModifiesPieceAssessment;

    /**
     * @var array
     */
    protected $mappings = [
...

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

2. Используйте шаблон стратегии

protected function mapForPresentKey(ONAData $onaData, $onaKey, array $mappingMetaData)
{
    if (Modifier::shouldModifyOnaData($mappingMetaData)) {
        $modifiedValue = Modifier::get($mappingMetaData)->modify($onaValue, $onaKey);
...

Используйте factory, чтобы создать экземпляр желаемого класса и вызвать в нем общий метод. Здесь Modifier получает желаемый класс Modifier, и в нем вызывается метод «modify». Это называется паттерном стратегии.

3. Используйте составной узор.

$installers = [
    Installation\CreateLaravelProject::class,
    Installation\DownloadSpark::class,
    Installation\UpdateComposerFile::class,
    Installation\ComposerUpdate::class,
    Installation\AddCoreProviderToConfiguration::class,
    Installation\RunSparkInstall::class,
    Installation\AddAppProviderToConfiguration::class,
    Installation\RunNpmInstall::class,
    Installation\RunGulp::class,
];

foreach ($installers as $installer) {
    (new $installer($this, $input->getArgument('name')))->install();
}

Смысл составного шаблона состоит в том, чтобы иметь возможность обращаться с коллекцией объектов, как если бы это был один объект. Приведенный выше код взят из команды Установщик Laravel Spark. Здесь небольшие задачи разделены на более мелкие классы, и во всех них указывается общий метод install, который затем вызывается в цикле.

4. Используйте сквозной доступ

class Invoice
{
    public function payment()
    {
        return new Payment($this);
    }
}

Чтобы вызвать методы класса Payment, мне не нужно создавать прокси-методы внутри класса Invoice. Вместо этого я могу создать единственный метод «payment» в классе Invoice -, который дает мне экземпляр класса Payment - и вызывать через него методы в классе Payment.

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

Я думаю, что становлюсь лучше в объектно-ориентированном подходе.