싱글톤에서 파사드까지
10339 단어 programmingphpwebdev
TL;DR And don't use facades either, if you don't have to.
더 나은 내일을 향해
"하지만 싱글톤은 사용하기가 너무 쉽습니다!"👴
// Singleton
class SomeService
{
public static function getInstance(): self {
if (self::$instance === null) {
self::$instance = new static();
}
return self::$instance;
}
}
또한 싱글톤의 유용성을 유지하면서 여전히 종속성 주입을 어느 정도 사용하는 것도 간단합니다.
완벽하지는 않지만 불완전한 세상을 위한 좋은 절충안입니다.
싱글톤과 파사드 사이에는 단 하나의 차이점이 있으며 인스턴스의 명시적 바인딩입니다.
파사드를 사용하기 전에 명시적 바인딩 호출이 발생해야 합니다.
// Facade
class SomeService
{
public static function getInstance(): self {
if (self::$instance === null) {
throw new LogicException();
}
return self::$instance;
}
public static function bind(?self $instance): void
{
self::$instance = $instance;
}
}
바인딩은 일반적으로 앱의 서비스 컨테이너를 사용하여 애플리케이션의 부트스트랩 단계에서 수행됩니다.
// Bootstrap the service container somehow...
$container = $bootstrap->container();
// Then bind the facade
SomeService::bind($container->get(SomeService::class));
이제 서비스 컨테이너를 통한 주입과 파사드 직접 사용이 모두 작동합니다.
이렇게 하면 레거시 코드가 계속 작동하도록 레거시 앱을 리팩터링할 수 있지만 최신 부분에 종속성 주입이 도입됩니다.
인터페이스 사용 예
파사드를 구현할 때 바인딩되는 인스턴스에 대해 항상 인터페이스를 사용해야 합니다. 이렇게 하면 그 뒤에 있는 구현을 교체할 수 있습니다.
final class EventBus
{
private static ?EventDispatcherInterface $instance = null;
public static function fire(EventInterface $event): void
{
if (self::$instance === null) {
throw new LogicException('The facade has not been bound to an instance.');
}
self::$instance->dispatch($event);
}
public static function bind(?EventDispatcherInterface $instance, bool $force = false): void
{
if (!$force && self::$instance !== null) {
throw new LogicException(...);
}
self::$instance = $instance;
}
}
앱 시작 중에 구성
$container = ...;
EventBus::bind($container->get(EventDispatcherInterface::class));
이제 DI와 파사드가 공존할 수 있습니다.
$event = new SomeEvent(...);
$dispatcher = $container->get(EventDispatcherInterface::class);
$dispatcher->dispatch($event);
EventBus::fire($event);
$force
메서드의 EventBus::bind
매개변수를 사용하는 이유를 물을 수 있습니다. 실용적인 목적을 위해: 파사드를 테스트하고 이를 위해 리바인딩하고 싶을 것입니다.또한 다음과 같이 이미 바인딩된 파사드를 바인딩하려고 시도할 때 설명적 예외를 throw하는 것이 좋습니다.
throw new LogicException(sprintf(
'The facade has already been bound.' . ' ' .
'This error might imply design flaws.' . ' ' .
'Consider injecting an %s implementation instead of using a facade.',
EventDispatcherInterface::class,
));
싱글톤은 모든 악의 근원입니까?
잘못된 생각을 하지 마십시오. 서비스에 대한 전역 액세스를 허용하기 위해 파사드를 사용해서는 안 됩니다. 여전히 종속성 주입 및 제어 역전(IoC) 원칙을 사용하려고 합니다.
Facades는 싱글톤을 구동하는 전역 액세스에 대한 동일한 나쁜 아이디어를 기반으로 합니다.
반면에 실용적인 경우도 있습니다(예: 로깅).
그리고 이미 싱글톤과 함께 제공되는 레거시 앱이 있습니다.
또는 종속성 주입 수단을 전혀 사용하지 않는 암흑기의 레거시 앱입니다.
파사드를 구현하고 DI 컨테이너를 활용하는 것은 이러한 상황에서 큰 진전이 될 수 있습니다.
그렇다면 싱글톤에 어떤 문제가 있습니까?
타이트한 커플링. 음, 모든 정적 호출 및
new
연산자 사용은 긴밀한 결합을 생성합니다.밀접하게 결합된 코드는 더 이상 사용되지 않는 구현을 새 구현으로 교체할 수 없기 때문에 확장하기 어렵고 유지하기가 더 어렵습니다. 밀접하게 결합된 코드는 코드의 많은 부분을 모킹해야 하기 때문에 테스트하기가 더 어렵습니다.
인터페이스를 통해 인스턴스에 바인딩되는 파사드로 작업할 때 파사드 뒤의 구현은 호출 코드를 수정하지 않고도 변경할 수 있습니다.
이렇게 하면 문제가 다소 완화됩니다.
싱글톤이 존재하는 이유는 무엇입니까?
싱글톤 패턴은 암흑기의 더 큰 악인 전역 변수를 해결했습니다. 싱글톤은 적어도 불변인 반면 전역 변수는 변덕스럽게 바뀔 수 있습니다.
싱글톤은 프로그래밍 역사의 일부이며 존중받아 마땅합니다. 그러나 현대 코드에는 그것들을 위한 자리가 없습니다.
테이크아웃
외관은 우리를 동시에 행복하고 편안하게 만드는 깨끗한 솔루션이 아닙니다. 그러나 싱글톤보다 더 나은 옵션입니다.
특히 기존 코드와의 호환성을 제공하는 동시에 더 밝은 미래를 향한 길을 닦는 레거시 앱에서 그렇습니다.
Reference
이 문제에 관하여(싱글톤에서 파사드까지), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/dakujem/from-singleton-to-facade-4agk텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)