인터페이스 독방 원리는 말합니다 :
클라이언트가 사용하지 않는 메소드에 의존해서는 안됩니다. ISP는 매우 큰 인터페이스를 더 작고 더 구체적인 인터페이스로 분할하여 클라이언트가 관심있는 방법에 대해서만 알면됩니다.
여기에 답변되지 않은 몇 가지 질문이 있습니다. 하나는:
얼마나 작습니까?
당신은 말합니다 :
현재 클라이언트의 요구 사항에 따라 모듈의 네임 스페이스를 나누어서 처리합니다.
이 수동 오리 타이핑 이라고 부릅니다 . 클라이언트에게 필요한 것만 노출하는 인터페이스를 빌드합니다. 인터페이스 분리 원리는 단순히 수동 오리 타이핑이 아닙니다.
그러나 ISP는 단순히 재사용 할 수있는 "일관된"역할 인터페이스를 요구하는 것이 아닙니다. "일관성있는"역할 인터페이스 디자인은 자체 역할 요구가있는 새로운 클라이언트의 추가를 완벽하게 막을 수 없습니다.
ISP 는 클라이언트가 서비스 변경으로 인한 영향으로부터 격리시키는 방법입니다. 변경 사항을 작성할 때 빌드가 더 빨라지도록 고안되었습니다. 물론 고객을 해치지 않는 것과 같은 다른 이점도 있지만 이것이 핵심이었습니다. 서비스 count()
기능 서명을 변경하는 경우 사용 count()
하지 않는 클라이언트를 편집하고 다시 컴파일 할 필요가없는 것이 좋습니다 .
이것이 내가 인터페이스 분리 원리에 관심을 갖는 이유입니다. 내가 중요하게 생각하는 것은 아닙니다. 실제 문제를 해결합니다.
따라서 적용 방식이 문제를 해결해야합니다. ISP를 적용하는 데 필요한 방법은 없습니다. 필요한 변경의 올바른 예만으로는 이길 수 없습니다. 시스템이 어떻게 변하고 있는지 살펴보고 사일런트를 방해 할 수있는 선택을해야합니다. 옵션을 살펴 보자.
먼저 스스로에게 물어보십시오 : 지금 서비스 인터페이스를 변경하기가 어렵습니까? 그렇지 않다면 밖으로 나가 진정 할 때까지 연주하십시오. 이것은 지적 운동이 아닙니다. 치료법이 질병보다 나쁘지 않은지 확인하십시오.
많은 클라이언트가 동일한 기능의 하위 집합을 사용하는 경우 "일관성있는"재사용 가능한 인터페이스가 필요합니다. 하위 집합은 서비스가 클라이언트에게 제공하는 역할로 생각할 수있는 하나의 아이디어에 중점을 둘 것입니다. 이것이 작동하면 좋습니다. 항상 작동하지는 않습니다.
많은 클라이언트가 다른 기능 하위 집합을 사용하는 경우 클라이언트가 실제로 여러 역할을 통해 서비스를 사용하고있을 수 있습니다. 괜찮지 만 역할을보기가 어렵습니다. 그들을 찾아서 애타게 시도하십시오. 클라이언트는 단순히 하나 이상의 인터페이스를 통해 서비스를 사용합니다. 서비스 캐스팅을 시작하지 마십시오. 서비스가 클라이언트에 두 번 이상 전달되는 것을 의미하는 경우. 그것은 효과가 있지만 서비스가 큰 진흙 공이 아닌지 나에게 의문을 제기합니다.
많은 클라이언트가 서로 다른 하위 집합을 사용하지만 클라이언트가 둘 이상을 사용할 수 있도록 허용하는 역할을 보지 못하면 인터페이스를 디자인하기 위해 오리 타이핑보다 나은 것은 없습니다. 인터페이스를 설계하는이 방법은 클라이언트가 사용하지 않는 하나의 기능에도 클라이언트가 노출되지 않도록하지만 새 클라이언트를 추가하면 항상 서비스 구현을 알 필요는 없지만 새 인터페이스를 추가해야합니다. 그것에 대해 역할 인터페이스를 집계하는 인터페이스가 수행합니다. 우리는 단순히 하나의 고통을 다른 것으로 바 꾸었습니다.
많은 클라이언트가 서로 다른 서브 세트를 사용하는 경우 겹치기 때문에 예측할 수없는 서브 세트가 필요한 새 클라이언트가 추가 될 것으로 예상되므로 서비스를 중단하지 않고보다 기능적인 솔루션을 고려하십시오. 처음 두 옵션이 작동하지 않고 패턴을 따르지 않고 더 많은 변화가 오는 나쁜 장소에 있기 때문에 각 기능을 제공하는 것이 좋습니다. 여기서 끝났다고해서 ISP가 실패한 것은 아닙니다. 실패한 것은 객체 지향 패러다임입니다. 단일 메소드 인터페이스는 ISP를 극도로 따릅니다. 키보드 타이핑은 상당히 좋지만 갑자기 인터페이스를 재사용 할 수 있습니다. 다시 한번,
그래서 그들은 실제로 매우 작아 질 수 있습니다.
가장 극단적 인 경우에 ISP를 적용하기위한 도전으로이 질문을했습니다. 그러나 극단을 피하는 것이 가장 좋습니다. 다른 SOLID 원리 를 적용하는 신중한 설계에서 이러한 문제는 일반적으로 거의 발생하지 않거나 중요하지 않습니다.
답변되지 않은 또 다른 질문은 다음과 같습니다.
이 인터페이스는 누가 소유합니까?
나는 계속해서 "라이브러리"라는 개념으로 설계된 인터페이스를 본다. 우리 모두는 당신이 무언가를하고있는 원숭이 참조 몽키도 코딩에 대해 유죄였습니다. 인터페이스도 마찬가지입니다.
라이브러리의 클래스를 위해 설계된 인터페이스를 볼 때 나는 다음과 같이 생각했습니다. 오,이 사람들은 전문가입니다. 인터페이스를 수행하는 올바른 방법이어야합니다. 내가 이해하지 못한 것은 라이브러리 경계에 자체 요구와 문제가 있다는 것입니다. 우선, 라이브러리는 클라이언트의 디자인을 완전히 무시합니다. 모든 경계가 같은 것은 아닙니다. 때로는 같은 경계조차도 다른 방법으로 교차 할 수 있습니다.
다음은 인터페이스 디자인을 보는 간단한 두 가지 방법입니다.
서비스 소유 인터페이스. 어떤 사람들은 서비스가 할 수있는 모든 것을 드러내 기 위해 모든 인터페이스를 설계합니다. IDE에서 리팩토링 옵션을 찾을 수 있습니다. IDE에서 피드를 제공하는 클래스를 사용하여 인터페이스를 작성합니다.
클라이언트 소유 인터페이스. ISP는 이것이 옳고 소유 한 서비스가 잘못되었다고 주장하는 것 같습니다. 클라이언트 요구 사항을 염두에두고 모든 인터페이스를 분리해야합니다. 클라이언트가 인터페이스를 소유하고 있으므로이를 정의해야합니다.
누가 맞습니까?
플러그인을 고려하십시오 :
누가 인터페이스를 소유합니까? 클라이언트? 서비스?
둘 다 밝혀졌습니다.
여기의 색상은 레이어입니다. 빨간색 레이어 (오른쪽)는 녹색 레이어 (왼쪽)에 대해 아무 것도 알고 있지 않습니다. 녹색 레이어는 빨간색 레이어를 건드리지 않고 변경하거나 교체 할 수 있습니다. 이렇게하면 모든 녹색 레이어를 빨간색 레이어에 꽂을 수 있습니다.
나는 무엇에 대해 알아야하고 무엇을 알아야하는지 알고 싶습니다. 나에게 "무엇을 알고 있는가?"는 가장 중요한 건축 질문입니다.
어휘를 명확하게하자 :
[Client] --> [Interface] <|-- [Service]
----- Flow ----- of ----- control ---->
클라이언트는 사용하는 것입니다.
서비스는 사용되는 것입니다.
Interactor
둘 다 발생합니다.
ISP는 클라이언트를위한 인터페이스를 분리한다고 말합니다. 좋아, 여기에 적용하자.
Presenter
(서비스)가 Output Port <I>
인터페이스를 지시해서는 안됩니다 . 인터페이스는 Interactor
클라이언트 (여기서는 클라이언트 역할)의 필요에 따라 좁혀 져야 합니다. 이는 Interactor
ISP 에 대한 인터페이스 지식 과 ISP에 따라 변경되어야 한다는 것을 의미합니다 . 그리고 이것은 괜찮습니다.
Interactor
(여기서는 서비스 역할을 함) Input Port <I>
인터페이스에 지시해서는 안됩니다 . 인터페이스는 Controller
(클라이언트)에게 필요한 것으로 좁혀 져야 합니다. 이는 Controller
ISP 에 대한 인터페이스 지식 과 ISP에 따라 변경되어야 한다는 것을 의미합니다 . 그리고 이것은 좋지 않습니다 .
두 번째는 빨간색 레이어가 녹색 레이어에 대해 알지 못하기 때문에 좋지 않습니다. ISP가 잘못 되었습니까? 글쎄요 절대적인 원칙은 없습니다. 인터페이스를 좋아하는 바보가 서비스가 할 수있는 모든 것을 보여주기위한 경우가 옳습니다.
적어도이 Interactor
유스 케이스가 아닌 다른 일을하지 않으면 옳습니다 . (가) 경우 Interactor
다른 사용 사례에 대한 일을이 이유가 없다 Input Port <I>
그들에 대해 알고있다가. Interactor
하나의 유스 케이스에만 집중할 수없는 이유 는 확실 하지 않으므로 이것이 문제가되지는 않지만 문제가 발생합니다.
그러나 input port <I>
인터페이스는 단순히 Controller
클라이언트 자체를 종속시킬 수 없으며 이것이 진정한 플러그인이 될 수 있습니다. 이것이 '라이브러리'경계입니다. 완전히 다른 프로그래밍 상점은 빨간 층이 출판 된 후 몇 년 동안 녹색 층을 쓸 수 있습니다.
'라이브러리'경계를 넘어서고 다른 쪽에서 인터페이스를 소유하지 않아도 ISP를 적용 할 필요가 있다고 생각하면 변경하지 않고 인터페이스를 좁힐 수있는 방법을 찾아야합니다.
그것을 뽑아내는 한 가지 방법은 어댑터입니다. 같은 클라이언트 사이에 넣어 Controler
와 Input Port <I>
인터페이스를 제공합니다. 어댑터는 Interactor
로 승인 하고 Input Port <I>
작업을 위임합니다. 그러나 Controller
역할 인터페이스 나 그린 레이어가 소유 한 인터페이스를 통해 고객이 필요로하는 것만 노출합니다 . 어댑터는 ISP 자체를 따르지 않지만 Controller
ISP를 즐기는 것과 같이 더 복잡한 클래스를 허용 합니다. 이 기능은 클라이언트보다 Controller
사용하는 어댑터 수보다 적은 수의 어댑터가 있고 라이브러리 경계를 넘어서서 게시 된 경우에도 라이브러리 변경이 중지되지 않는 비정상적인 상황에있을 때 유용합니다. Firefox를보고 있습니다. 이제 이러한 변경으로 인해 어댑터가 손상되었습니다.
이것이 무엇을 의미합니까? 정직하게 당신이해야 할 일을 말해 줄 수있는 충분한 정보를 제공하지 않았다는 것을 의미합니다. ISP를 따르지 않는 것이 문제를 일으키는 지 모르겠습니다. 그것을 따르는 것이 더 이상 문제를 일으키지 않을지 모르겠습니다.
나는 당신이 간단한지도 원리를 찾고 있다는 것을 알고 있습니다. ISP는 그렇게하려고 노력합니다. 그러나 그것은 많은 말이 남지 않습니다. 나는 그것을 믿는다. 그렇습니다. 정당한 이유없이 고객이 사용하지 않는 방법에 의존하도록 강요하지 마십시오!
플러그인을 수용 할 무언가를 설계하는 등의 정당한 이유가있는 경우, ISP 원인을 따르지 않는 문제 (클라이언트를 중단하지 않고 변경하기 어렵다)와이를 완화시키는 방법 ( 안정적인 Interactor
또는 최소한 Input Port <I>
하나의 안정에 집중 하거나 사용 사례).