늦게 대답했지만 저항 할 수 없습니다.
X 대부분의 클래스는 Y에 반합니까, 반 패턴입니까?
대부분의 경우, 생각없이 적용되는 대부분의 규칙은 (이 규칙을 포함하여) 크게 잘못 될 것입니다.
설계 상이 아니라 절망에 빠진, 정확하고, 더럽고, 절차적인 코드의 혼란 속에서 객체의 탄생에 대한 이야기를하겠습니다.
내 인턴과 나는 웹 페이지를 긁어 모으기 위해 약간의 버리기 코드를 신속하게 만들기 위해 페어 프로그래밍입니다. 우리는이 코드가 오래 살 것이라고 기대할 이유가 없으므로 작동하는 것을 방황하고 있습니다. 우리는 전체 페이지를 줄로 잡고 상상할 수있는 가장 놀랍도록 부서지기 쉬운 방법으로 필요한 것을 잘라냅니다. 판단하지 마십시오. 효과가있다.
이제이 작업을 수행하는 동안 도마를 수행하는 정적 메소드를 만들었습니다. 제 인턴은 여러분과 매우 비슷한 DTO 수업을 만들었습니다 CatData
.
내가 처음 DTO를 보았을 때 그것은 나를 괴롭혔다. 자바가 뇌에 해를 입힌 몇년 간의 피해는 공공 장소에서 반동을 일으켰습니다. 그러나 우리는 C #에서 일하고있었습니다. C #은 데이터를 변경할 수 없거나 나중에 캡슐화 할 수있는 권리를 보존하기 위해 조기 게터와 세터가 필요하지 않습니다. 인터페이스를 변경하지 않고도 언제든지 추가 할 수 있습니다. 아마도 중단 점을 설정할 수 있습니다. 고객에게 그것에 대해 말하지 않아도됩니다. 예 C #. 부 자바.
그래서 나는 내 혀를 잡았다. 그가 정적 메소드를 사용하여 이것을 사용하기 전에 초기화하는 것을 보았습니다. 우리는 그들 중 약 14 명을 가졌습니다. 추악했지만 우리는 돌볼 이유가 없었습니다.
그런 다음 다른 곳에서 필요했습니다. 우리는 코드를 복사하여 붙여 넣기를 원했습니다. 14 줄의 초기화가 진행되고 있습니다. 고통스러워지기 시작했다. 그는 주저하고 아이디어를 요구했다.
마지 못해 나는 "물건을 고려하겠습니까?"
그는 자신의 DTO를 되돌아보고 혼란스럽게 얼굴을 망쳤다. "대상이다".
"나는 진짜 물건을 의미한다"
"응?"
"내가 뭔가 보여 줄게. 그것이 유용한 지 결정한다"
나는 새로운 이름을 선택하고 다음과 같이 보이는 것을 빠르게 채찍질했습니다.
public class Cat{
CatData(string catPage) {
this.catPage = catPage
}
private readonly string catPage;
public string name() { return chop("name prefix", "name suffix"); }
public string weight() { return chop("weight prefix", "weight suffix"); }
public string image() { return chop("image prefix", "image suffix"); }
private string chop(string prefix, string suffix) {
int start = catPage.indexOf(prefix) + prefix.Length;
int end = catPage.indexOf(suffix);
int length = end - start;
return catPage.Substring(start, length);
}
}
정적 메소드가 아직 수행하지 않은 것은 없습니다. 그러나 이제는 14 개의 정적 메서드를 작업 한 데이터와 함께 사용할 수있는 클래스로 빨아 들였습니다.
인턴이 강요하지 않았습니다. 나는 방금 그것을 제안했고 그가 정적 방법을 고수하고 싶은지 결정하게했습니다. 나는 그가 이미 일한 것에 충실 할 것이라고 생각하여 집으로 갔다. 그 다음날 나는 그가 여러 곳에서 그것을 사용하고 있음을 발견했다. 그것은 여전히 추악하고 절차적인 나머지 코드를 어지럽히 지만이 복잡한 부분은 이제 객체 뒤에 숨겨져 있습니다. 조금 나아졌습니다.
지금 당신이 이것에 접근 할 때마다 그것은 상당한 일을하고 있습니다. DTO는 빠른 캐시 값입니다. 나는 그것에 대해 걱정했지만 사용 코드를 건드리지 않고 필요할 때 캐싱을 추가 할 수 있음을 깨달았습니다. 그래서 우리가 걱정할 때까지 귀찮게하지 않습니다.
나는 항상 DTO보다 OO 객체를 고수해야한다고 말하고 있습니까? 아닙니다. DTO는 움직이는 방법을 방해하는 경계를 넘어야 할 때 빛납니다. DTO는 그 자리에 있습니다.
그러나 OO 객체도 마찬가지입니다. 두 도구를 모두 사용하는 방법을 배웁니다. 각 비용에 대해 알아보십시오. 문제, 상황 및 인턴이 결정하도록 배우십시오. 도그마는 당신의 친구가 아닙니다.
내 대답은 이미 엄청나게 길기 때문에 코드를 검토하여 몇 가지 오해를 기각하도록하겠습니다.
예를 들어, 클래스에는 보통 다음과 같은 클래스 멤버와 메소드가 있습니다.
public class Cat{
private String name;
private int weight;
private Image image;
public void printInfo(){
System.out.println("Name:"+this.name+",weight:"+this.weight);
}
public void draw(){
//some draw code which uses this.image
}
}
생성자는 어디에 있습니까? 이것이 유용한 지 알기에는 충분하지 않습니다.
그러나 단일 책임 원칙과 공개 폐쇄 원칙에 대해 읽은 후 정적 메소드 만 사용하여 클래스를 DTO와 도우미 클래스로 분리하는 것을 선호합니다.
public class CatData{
public String name;
public int weight;
public Image image;
}
public class CatMethods{
public static void printInfo(Cat cat){
System.out.println("Name:"+cat.name+",weight:"+cat.weight);
}
public static void draw(Cat cat){
//some draw code which uses cat.image
}
}
CatData의 책임은 데이터 만 유지하고 메서드에 신경 쓰지 않기 때문에 단일 책임 원칙에 적합하다고 생각합니다 (CatMethods에도 해당).
단일 책임 원칙 (Single Responsibility Principle)이라는 이름으로 많은 바보 같은 일을 할 수 있습니다. Cat Strings와 Cat int를 분리해야한다고 주장 할 수 있습니다. 해당 그리기 방법과 이미지에는 모두 고유 한 클래스가 있어야합니다. 실행중인 프로그램은 하나의 책임이므로 클래스는 하나만 있어야합니다. :피
나에게 단일 책임 원칙을 따르는 가장 좋은 방법은 상자에 복잡성을 넣어서 숨길 수있는 좋은 추상화를 찾는 것입니다. 사람들에게 좋은 이름을 줄 수 있다면 사람들이 내면을 보았을 때 찾은 것에 놀라지 않게 할 수 있습니다. 그것은 더 많은 결정을 지시하기를 기대하며 그것은 문제를 요구합니다. 솔직히 두 코드 목록 모두 그렇게하므로 SRP가 왜 중요한지 알 수 없습니다.
또한 새로운 메소드를 추가해도 CatData 클래스를 변경할 필요가 없기 때문에 공개 폐쇄 원칙에 적합합니다.
음 ... 아니. 공개 폐쇄 원칙은 새로운 메소드 추가에 관한 것이 아닙니다. 이전 메소드의 구현을 변경하고 아무것도 편집하지 않아도됩니다. 오래된 방법이 아닌 당신을 사용하는 것은 없습니다. 대신 다른 곳에 새 코드를 작성하십시오. 어떤 형태의 다형성이 그렇게 잘 할 것입니다. 여기서 보지 마십시오.
내 질문은, 그것이 좋은지 아니면 반 패턴입니까?
내가 어떻게 알아? 보세요, 어느 쪽이든하는 것은 장점과 비용이 있습니다. 코드를 데이터와 분리하면 다른 코드를 다시 컴파일하지 않고도 변경할 수 있습니다. 아마도 그것은 당신에게 매우 중요합니다. 어쩌면 코드가 무의미하게 복잡해질 수 있습니다.
그것이 기분이 나아진다면 Martin Fowler가 매개 변수 객체를 호출하는 것과 멀지 않습니다 . 프리미티브를 객체로 가져갈 필요는 없습니다.
내가 당신이하고 싶은 것은 코딩 스타일에서 분리를 수행하거나하지 않는 방법에 대한 감각을 개발하는 것입니다. 믿거 나 말거나 스타일을 선택하지 않아도되기 때문입니다. 당신은 단지 당신의 선택에 따라 살아야합니다.