시스템이 복잡 하다고해서 시스템을 복잡하게 만들어야한다는 의미는 아닙니다 . 다음과 같이 종속성 (또는 공동 작업자)이 너무 많은 클래스가있는 경우 :
public class MyAwesomeClass {
public class MyAwesomeClass(IDependency1 _d1, IDependency2 _d2, ... , IDependency20 _d20) {
// Assign it all
}
}
... 너무 복잡 해져서 실제로 SRP를 따르지 않고 있습니까? 당신이 무엇을 기록한 경우 나는 셨을 텐데요 MyAwesomeClass
A의 수행 CRC 카드 는 인덱스 카드에 맞지 않는 것 또는 당신이 정말로 작은 읽기 어려운 문자에 작성해야합니다.
당신이 여기에있는 것은 당신의 사람들이 대신 인터페이스 분리 원칙을 따랐으며 극단적으로 가져 갔을 수도 있지만 그것은 완전히 다른 이야기입니다. 의존성이 도메인 객체 (일어남)라고 주장 할 수는 있지만 동시에 20 개의 도메인 객체를 처리하는 클래스를 사용하면 너무 멀리 확장됩니다.
TDD는 수업이 얼마나 많은지를 보여주는 좋은 지표입니다. 둔하게 넣어; 테스트 방법에 작성하는 데 시간 MyAwesomeClass
이 오래 걸리는 설정 코드가있는 경우 (테스트 리팩터링하더라도) 할 일이 너무 많습니다.
이 수수께끼를 어떻게 해결합니까? 책임을 다른 수업으로 옮깁니다. 이 문제가있는 수업에서 취할 수있는 몇 가지 단계가 있습니다.
- 여러분의 학급이 그들과 함께하는 모든 행동 (또는 책임)을 파악하십시오.
- 밀접하게 관련된 종속성에 따라 작업을 그룹화하십시오.
- 재 선교! 즉, 식별 된 각 조치를 새 클래스 또는 다른 클래스로 리팩토링합니다.
리팩토링 책임에 대한 추상적 인 예
하자 C
여러 종속성이 클래스가 될 D1
, D2
, D3
, D4
적은 사용 리팩토링 할 필요가있다. C
의존성 을 호출 하는 메소드를 식별 하면 간단한 목록을 작성할 수 있습니다.
D1
- performA(D2)
,performB()
D2
- performD(D1)
D3
- performE()
D4
- performF(D3)
목록을 보면 우리가 볼 수 D1
와 D2
클래스가 어떻게 든 함께 필요에 따라 서로 관련이 있습니다. 우리는 또한 그 D4
요구를 볼 수 있습니다 D3
. 그래서 우리는 두 그룹화가 있습니다 :
Group 1
- D1
<->D2
Group 2
-- D4
>D3
그룹화는 이제 클래스에 두 가지 책임이 있음을 나타냅니다.
Group 1
-서로 필요한 두 객체 호출을 처리하기위한 것입니다. 어쩌면 클래스 C
가 두 종속성을 모두 처리해야 할 필요성을 없애고 그 중 하나를 대신 호출 하도록 할 수 있습니다 . 이 그룹에서는에 D1
대한 참조 가 있을 수 있습니다 D2
.
Group 2
-다른 책임은 한 개체가 다른 개체를 호출해야합니다. 수업 대신 D4
처리 할 수 없습니까 D3
? 그런 다음 우리는 아마 제거 할 수있는 D3
클래스에서 C
시켜서 D4
대신 호출을한다.
예제가 매우 추상적이며 많은 가정을하므로 돌로 설정된 대답을 취하지 마십시오. 나는 이것을 리팩토링하는 더 많은 방법이 있다고 확신하지만, 적어도 단계는 클래스를 나누는 대신 책임을 옮기는 일종의 프로세스를 얻는 데 도움이 될 수 있습니다.
편집하다:
댓글 중 @Emmad Karem의 말 :
"클래스에 생성자에 20 개의 매개 변수가있는 경우 팀에서 SRP가 무엇인지 잘 알고있는 것처럼 들리지 않습니다. 한 가지만 수행하는 클래스가있는 경우 20 개의 종속성이있는 방법은 무엇입니까?"- Customer 클래스가 있으면 생성자에 20 개의 매개 변수가있는 것이 이상하지 않습니다.
DAO 객체에는 생성자에서 설정해야하는 많은 매개 변수가있는 경향이 있으며 매개 변수는 일반적으로 문자열과 같은 간단한 유형입니다. 그러나 Customer
클래스 의 예에서 다른 클래스 내에 속성을 그룹화하여 작업을 단순화 할 수 있습니다. Address
거리 가있는 클래스와 Zipcode
우편 번호가 포함 된 클래스가 있고 데이터 유효성 검사와 같은 비즈니스 로직도 처리합니다.
public class Address {
private String street1;
//...
private Zipcode zipcode;
// easy to extend
public bool isValid() {
return zipcode.isValid();
}
}
public class Zipcode {
private string zipcode;
public bool isValid() {
// return regex match that zipcode contains numbers
}
}
이 내용은 블로그 게시물 "Java에서 String을 사용하지 마십시오 (또는 자주 사용하지 마십시오)" 에서 자세히 설명 합니다. 하위 객체를보다 쉽게 만들 수 있도록 생성자 또는 정적 메서드를 사용하는 대신 유체 빌더 패턴을 사용할 수 있습니다 .