# 03. Классы и объекты (SOLID, DI, ServiceLocator)

[← Оглавление](./index.md)

---

## Принцип единственной ответственности (SRP)

**ПЛОХО — КЛАСС ДЕЛАЕТ ВСЁ СРАЗУ**
```php
class LeadManager {
    public function create(array $data): void { /* ... */ }
    public function sendEmail(string $message): void { /* ... */ }
    public function log(string $action): void { /* ... */ }
}
```

**ХОРОШО — РАЗДЕЛЕНИЕ ОТВЕТСТВЕННОСТЕЙ**
```php
class LeadCreationService {
    public function __construct(
        private \Bitrix\Crm\Service\Container $crmContainer,
        private LeadNotificationService $notificationService,
        private \Psr\Log\LoggerInterface $logger,
    ) {}
    
    public function createFromArray(array $data): \Bitrix\Crm\Item {
        // только логика создания лида
    }
}
```

---

## Предпочитайте композицию наследованию

**ПЛОХО — НАСЛЕДОВАНИЕ ОТ УСТАРЕВШЕГО КЛАССА**
```php
class CustomDealProcessor extends \CCrmDeal {
    public function process($dealId) {
        $this->Update($dealId, ['STAGE_ID' => 'WON']);
    }
}
```

**ПРАВИЛЬНО — ЧЕРЕЗ CONTAINER**
```php
class DealProcessor {
    public function __construct(
        private \Bitrix\Crm\Service\Container $container,
    ) {}
    
    public function markAsWon(int $dealId): void {
        $factory = $this->container->getFactory(\CCrmOwnerType::Deal);
        $deal = $factory->getItem($dealId);
        if ($deal === null) {
            throw new \Bitrix\Main\ObjectNotFoundException("Deal #{$dealId} not found");
        }
        $deal->setStageId('WON');
        $result = $factory->getUpdateOperation($deal)->launch();
        if (!$result->isSuccess()) {
            throw new \RuntimeException(implode(', ', $result->getErrorMessages()));
        }
    }
}
```

---

## ServiceLocator Bitrix для внедрения зависимостей

**ПЛОХО — РУЧНОЕ СОЗДАНИЕ ЗАВИСИМОСТЕЙ ПОВСЮДУ**
```php
// В каждом месте использования:
$logger = new FileLogger('/local/logs/app.log');
$factory = \Bitrix\Crm\Service\Container::getInstance()
    ->getFactory(\CCrmOwnerType::Lead);
$service = new LeadCreationService($factory, new LeadNotificationService(), $logger);
```

**ХОРОШО — РЕГИСТРАЦИЯ ОДИН РАЗ, ПОЛУЧЕНИЕ ВЕЗДЕ**
```php
use Bitrix\Main\DI\ServiceLocator;

// Один раз:
$serviceLocator = ServiceLocator::getInstance();
$serviceLocator->addInstanceLazy(
    LeadCreationService::class,
    static function () use ($serviceLocator): LeadCreationService {
        return new LeadCreationService(
            \Bitrix\Crm\Service\Container::getInstance(),
            $serviceLocator->get(LeadNotificationService::class),
            $serviceLocator->get(\Psr\Log\LoggerInterface::class),
        );
    }
);

// Получение в любом месте приложения:
$service = ServiceLocator::getInstance()->get(LeadCreationService::class);
```

---

## Избегайте статических методов для бизнес-логики

**ПЛОХО — ПРЯМОЙ ВЫЗОВ УСТАРЕВШЕГО API**
```php
$leadId = \CCrmLead::Add(['TITLE' => 'Новый лид']);
```

**ХОРОШО — ОБОРАЧИВАЕМ В СЕРВИС**
```php
class LeadService {
    public function __construct(private \Bitrix\Crm\Service\Factory $factory) {}
    
    public function create(string $title): \Bitrix\Crm\Item {
        $lead = $this->factory->createItem();
        $lead->setTitle($title);
        return $this->factory->getCreateOperation($lead)->launch()->getItem();
    }
}
```