대부분의 클래스를 데이터 필드 전용 클래스와 메소드 전용 클래스 (가능한 경우)로 분리하는 것이 좋거나 반 패턴입니까?


10

예를 들어, 클래스에는 보통 다음과 같은 클래스 멤버와 메소드가 있습니다.

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에도 해당). 또한 새로운 메소드를 추가해도 CatData 클래스를 변경할 필요가 없기 때문에 공개 폐쇄 원칙에 적합합니다.

내 질문은, 그것이 좋은지 아니면 반 패턴입니까?


15
새로운 개념을 배웠기 때문에 맹목적으로 모든 일을하는 것은 항상 반 패턴입니다.
Kayaman 2016 년

4
데이터를 수정하는 메소드와 데이터를 분리하는 것이 더 좋은 경우 클래스의 요점은 무엇입니까? 그것은 비 객체 지향 프로그래밍처럼 들립니다 (확실히 그 자리를 차지합니다). 이것이 "객체 지향"으로 태그되어 있기 때문에 OOP가 제공하는 도구를 사용하고 싶다고 생각하십니까?
user1118321 2016 년

4
SRP가 너무 잘못 이해되어 금지되어야한다는 것을 입증하는 또 다른 질문. 공공 장소에 데이터를 보관하는 것은 책임아닙니다 .
user949300

1
@ user949300, 클래스가 해당 필드를 담당하는 경우 앱의 다른 곳으로 이동하면 영향이 없습니다. 또는 달리 말하면, 당신은 착각합니다 : 100 %는 책임입니다.
David Arno

2
@DavidArno 및 R Schmitz : 포함 필드는 SRP의 목적에 대한 책임으로 간주되지 않습니다. 그렇다면 모든 것이 DTO가되기 때문에 OOP가 없을 수 있으며 별도의 클래스에는 데이터 작업을위한 프로 시저가 포함됩니다. 단일 책임은 단일 이해 관계자 와 관련이 있습니다. (이것은 교장의 각 반복마다 약간 변경되는 것처럼 보입니다)
user949300

답변:


10

두 가지 극단 ( "한 개체의 모든 개인 메서드 및 모든 (관련되지 않은) 메서드"대 "공개 및 개체 내의 메서드 없음")을 표시했습니다. IMHO 좋은 OO 모델링은 그들 중 어느 것도 아니며 , 스위트 스팟은 중간에 있습니다.

클래스에 속하는 메소드 또는 논리와 외부에 속하는 메소드에 대한 한 가지 리트머스 테스트는 메소드가 가져올 종속성을 살펴 보는 것입니다. 추가 의존성을 도입하지 않는 메소드 는 주어진 객체의 추상화에 잘 맞는 한 괜찮습니다 . 추가 외부 종속성 (예 : 도면 라이브러리 또는 I / O 라이브러리)이 필요한 방법은 거의 적합하지 않습니다. 의존성 주입을 사용하여 의존성을 사라지게하더라도 도메인 클래스 내에 그러한 메소드를 배치하는 것이 정말로 필요한 경우 여전히 두 번 생각할 것입니다.

따라서 모든 멤버를 공개해서는 안되며 클래스 내부의 객체에서 모든 작업에 대한 메소드를 구현할 필요도 없습니다. 대체 제안은 다음과 같습니다.

public class Cat{
    private String name;
    private int weight;
    private Image image;

    public String getInfo(){
        return "Name:"+this.name+",weight:"+this.weight;
    }
    public Image getImage(){
        return image;
    }
}

이제 Cat객체는 모든 속성을 공개적으로 노출하지 않고도 주변 코드를 쉽게 구현 printInfo하고 구현할 수있는 충분한 로직을 제공합니다 draw. 이러한 두 가지 방법에 대한 올바른 장소는 대부분의 아마 신 클래스하지 않습니다 CatMethods(이후 printInfo그리고 draw나는 그들이 같은 클래스에 속하는 매우 가능성이 생각, 그래서 아마 다른 문제이다).

CatDrawingController구현을 상상할 수 있습니다 draw(그리고 Canvas 객체를 얻기 위해 의존성 주입을 사용합니다). 또한 일부 콘솔 출력을 구현하고 사용하는 다른 클래스를 상상할 수 있습니다 getInfo( printInfo이 컨텍스트에서는 더 이상 사용되지 않을 수 있음). 그러나 이에 대한 합리적인 결정을 내리려면 상황과 Cat수업이 실제로 어떻게 사용 되는지 알아야합니다 .

이것이 실제로 Fowler의 Anemic Domain Model 비평가를 해석 한 방식 입니다. 일반적으로 재사용 가능한 로직 (외부 의존성없이)에 대해서는 도메인 클래스 자체가 좋은 곳이므로이를 사용해야합니다. 그러나 이것이 그 반대의 논리를 구현한다는 의미는 아닙니다.

또한 위의 예는 (im) 변경 가능성에 대한 결정을 내릴 여지를 남겨 둡니다. 경우 Cat클래스가 어떤 세터를 노출하지 않습니다 Image자체 불변,이 디자인을 만들 수 있습니다 Cat불변 (이는 DTO 접근하지 않습니다). 그러나 불변성이 필요하지 않거나 귀하의 경우에 도움이되지 않는다고 생각되면 그 방향으로 갈 수도 있습니다.


행복한 downvoter를 트리거하면 지루해집니다. 비평가가 있으시면 알려주세요. 오해가 있으시면 기꺼이 이해해 드리겠습니다.
Doc Brown

나는 일반적으로 귀하의 답변에 동의하지만 ... getInfo()이 질문을하는 사람에게는 오해의 소지가 있습니다. 그것은 미묘 프리젠 테이션 책임을 혼합 printInfo()의 목적을 격파 않는 DrawingController클래스
아드리아누 Repetti에게

@AdrianoRepetti의 목적을 어기는 것을 보지 못했습니다 DrawingController. 나는 그것을 동의 getInfo()하고 printInfo()끔찍한 이름입니다. 고려 toString()하고printTo(Stream stream)
candied_orange

@ 솔직히 이름에 관한 것이 아니라 그 기능에 관한 것입니다. 이 코드는 프리젠 테이션 세부 사항에 관한 것이며 처리 된 내용과 논리가 아닌 출력을 효과적으로 추상화했습니다.
Adriano Repetti 2016 년

@AdrianoRepetti : 솔직히 이것은 원래의 질문에 맞고 나의 요점을 보여주기 위해 고안된 예일뿐입니다. 실제 시스템에는 물론 더 나은 방법과 이름에 대한 결정을 내릴 수있는 주변 환경이 있습니다.
Doc Brown

6

늦게 대답했지만 저항 할 수 없습니다.

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가 매개 변수 객체를 호출하는 것과 멀지 않습니다 . 프리미티브를 객체로 가져갈 필요는 없습니다.

내가 당신이하고 싶은 것은 코딩 스타일에서 분리를 수행하거나하지 않는 방법에 대한 감각을 개발하는 것입니다. 믿거 나 말거나 스타일을 선택하지 않아도되기 때문입니다. 당신은 단지 당신의 선택에 따라 살아야합니다.


2

10 년 넘게 개발자들 사이에서 논쟁을 일으킨 토론 주제를 우연히 발견했습니다. 2003 년 Martin Fowler 는 이러한 데이터와 기능의 분리를 설명하기 위해 "ADM (Anaemic Domain Model)"이라는 문구를 만들었습니다 . 그와 그에 동의하는 다른 사람들은 "리치 도메인 모델"(데이터와 기능이 혼합 된)이 "적절한 OO"이고 ADM 접근 방식은 비 OO 방지 패턴이라고 주장합니다.

이 주장을 일축하는 사람들이 항상 있었으며, 논쟁의 여지가 기능 개발 기술의 더 많은 개발자들에 의해 채택되면서 최근 몇 년 동안 점점 커지고있다. 이러한 접근 방식은 데이터와 기능 문제의 분리를 적극적으로 장려합니다. 데이터는 가능한 한 불변해야하므로 변경 가능한 상태의 캡슐화는 고려되지 않습니다. 이러한 상황에서 해당 데이터에 기능을 직접 연결하면 이점이 없습니다. OO가 아닌지 아닌지는 그러한 사람들에게는 전혀 관심이 없습니다.

에 관계없이 당신이 앉아 울타리의 어느 쪽의 정적 메소드의 사용 (I가 매우 확고하게 앉아 BTW 측 "마틴 파울러는 오래된 토시의 부하를 말하고") printInfodraw거의 보편적으로 눈살을 찌푸렸다시입니다. 단위 테스트를 작성할 때 정적 메소드는 조롱하기가 어렵습니다. 따라서 부작용 (예 : 일부 화면이나 다른 장치로 인쇄 또는 그림 그리기)이있을 경우 정적이거나 출력 위치가 매개 변수로 전달되어야합니다.

따라서 인터페이스를 가질 수 있습니다.

public interface CatMethods {
    void printInfo(Cat cat);
    void draw(Cat cat);
}

그리고 런타임에 나머지 시스템에 주입되는 구현 (다른 구현은 테스트에 사용됨) :

internal class CatMethodsForScreen implements CatMethods {
    public void printInfo(Cat cat) {
        System.out.println("Name:"+cat.name+",weight:"+cat.weight);
    }

    public void draw(Cat cat) {
        //some draw code which uses cat.image
    }
}

또는 추가 매개 변수를 추가하여 해당 방법에서 부작용을 제거하십시오.

public static class CatMethods {
    public static void printInfo(Cat cat, OutputHandler output) {
        output.println("Name:"+cat.name+",weight:"+cat.weight);
    }

    public static void draw(Cat cat, Canvas canvas) {
        //some draw code which uses cat.image and draws it on canvas
    }
}

그러나 왜 처음부터 기능적 언어를 사용하는 대신 Java와 같은 OO 언어를 기능적 언어로 바꾸려고합니까? "저는 Java를 싫어하지만 모든 사람이 Java를 사용해야하므로 적어도 내 방식으로 작성해야합니다." OO 패러다임이 어떤 식 으로든 구식이며 구식이라고 주장하지 않는 한. 저는 "X를 원한다면 어디서 구할 수 있는지 알고 있습니다"라는 학교에 가입했습니다.
Kayaman

@Kayaman, " 저는"X를 원한다면 어디서 구할 수 있는지 알고 있습니다 "라고 생각 합니다. 난 아니야 나는 그 태도가 근시안적이고 약간 공격적이라는 것을 안다. Java를 사용하지 않지만 C #을 사용하고 일부 "실제 OO"기능을 무시합니다. 상속, 상태 저장 객체 등을 신경 쓰지 않고 많은 정적 메소드와 봉인 된 (최종) 클래스를 작성합니다. C #을 중심으로 한 툴링 및 커뮤니티 규모는 최고입니다. F #의 경우 훨씬 나쁩니다. 그래서 저는 "X를 원한다면 X를 현재 툴링에 추가하도록 요청하십시오"라고 생각합니다.
David Arno

1
언어의 측면을 무시하는 것은 다른 언어의 기능을 혼합하고 일치시키는 것과는 많이 다릅니다. 프로그래밍과 같은 부정확 한 과학에서 규칙 (또는 원칙)을 따르려고 시도하는 것이 효과가 없기 때문에 "진정한 OO"도 쓰려고하지 않습니다. 물론 규칙을 알고 있어야 규칙을 어길 수 있습니다. 기능을 맹목적으로 다루는 것은 언어 개발에 좋지 않을 수 있습니다. 위반은 없지만 FP 장면의 일부 IMHO는 "FP가 얇게 썬 빵 이후 가장 큰 것이므로 사람들이 이해하지 못하는 이유"라고 생각하는 것 같습니다. 나는 OO 또는 Java가 "최고"라고 말하거나 생각하지 않을 것입니다.
Kayaman

1
@Kayaman, 그러나 "다른 언어의 기능을 혼합하고 일치 시키려고한다"는 것은 무엇을 의미합니까? "Java는 OO 언어"이기 때문에 기능적 기능을 Java에 추가해서는 안된다고 주장하고 있습니까? 그렇다면 내 견해로는 근시안적 인 주장입니다. 개발자의 요구에 따라 언어를 발전 시키십시오. 그들이 다른 언어로 바꾸도록 강요하는 것은 잘못된 접근법이라고 생각합니다. 어떤 "FP 옹호자들"이 FP가 최고라고 생각합니다. 그리고 일부 "OO 옹호자들"은 OO가 "전쟁에서 승리했기 때문에 분명히 우위에있다"는 것에 대해 1 위를 차지합니다. 둘 다 무시하십시오.
David Arno

1
나는 안티 FP가 아닙니다. Java에서 유용한 곳에서 사용합니다. 그러나 프로그래머가 "I want this"라고 말하면 클라이언트가 "I want this"라고 말하는 것과 같습니다. 프로그래머는 언어 디자이너가 아니며 클라이언트는 프로그래머가 아닙니다. OP의 "솔루션"이 눈살을 찌푸리게한다고 말했기 때문에 귀하의 답변을 찬성했습니다. 이 질문에 대한 의견은 간결합니다. 즉, 그는 OO 언어로 절차 적 프로그래밍을 재창조했습니다. 당신이 보여 주듯이 일반적인 아이디어는 요점을 가지고 있습니다. 비 핵심 도메인 모델이 데이터와 동작이 배타적이라는 의미는 아니며 외부 렌더러 나 발표자는 금지됩니다.
Kayaman 2016 년

0

DTO-데이터 전송 객체

그냥 유용합니다. 프로그램 또는 시스템간에 데이터를 분류하려는 경우 DTO가 데이터 구조 및 형식에만 관련된 개체의 관리 가능한 하위 집합을 제공하기 때문에 바람직합니다. 기본 데이터가 변경되지 않는 한 여러 시스템에서 복잡한 방법으로 업데이트를 동기화 할 필요가 없다는 장점이 있습니다.

OO의 핵심은 데이터와 해당 데이터에 작용하는 코드를 서로 밀접하게 묶는 것입니다. 논리적 객체를 별도의 클래스로 분리하는 것은 일반적으로 나쁜 생각입니다.


-1

많은 디자인 패턴과 원칙이 상충되며 궁극적으로 훌륭한 프로그래머라는 판단만으로 특정 문제에 적용 할 패턴을 결정하는 데 도움이됩니다.

제 생각 에는 디자인을 더 복잡하게 만들만한 강력한 이유가 없다면 작업을 할 수있는 가장 단순한 일을하는 것이 원칙입니다. 특정 예에서, 첫 번째 설계를 선택합니다. 이는 동일한 클래스에서 데이터와 함수를 함께 사용하는보다 전통적인 객체 지향 접근 방식입니다.

다음은 응용 프로그램에 대해 스스로에게 물어볼 수있는 몇 가지 질문입니다.

  • Cat 이미지를 렌더링하는 다른 방법을 제공해야합니까? 그렇다면 상속이 편리한 방법이 아닐까요?
  • 내 Cat 클래스는 다른 클래스에서 상속 받거나 인터페이스를 만족시켜야합니까?

이 중 하나라도 예라고 대답하면 별도의 DTO 및 기능 클래스를 사용하여보다 복잡한 설계로 이어질 수 있습니다.


-1

좋은 패턴입니까?

사람들은 다른 생각의 학교를 따르기 때문에 아마도 다른 대답을 얻을 것입니다. 그래서 시작하기 전에 :이 답변은 Robert C. Martin이 "Clean Code"책에서 설명한 것처럼 객체 지향 프로그래밍에 따른 것입니다.


"참"OOP

내가 아는 한 OOP에 대한 두 가지 해석이 있습니다. 대부분의 사람들에게 그것은 "객체는 클래스"로 요약됩니다.

그러나 다른 생각의 학교가 더 도움이된다는 것을 알게되었습니다. "물체는 무언가를하는 것입니다." 클래스로 작업하는 경우 각 클래스는 " 데이터 홀더 "또는 객체 중 하나입니다 . 데이터 보유자는 데이터 (duh)를 보유하고 객체는 일을합니다. 데이터 보유자가 메소드를 가질 수 없다는 것을 의미 하지는 않습니다 ! (A)의 생각 listA가 : list정말하지 않습니다 아무것도하지만, 시행, 메소드가 이 데이터를 보유하는 방법을 .

데이터 홀더

당신은 Cat데이터 소유자의 대표적인 예이다. 물론, 프로그램 밖에서 고양이는 무언가를하는 것이지만, 프로그램 안에서 a Cat는 String name, int weight및 Image image입니다.

이 데이터 홀더는하지 않습니다 어떻게 그들이 비즈니스 로직을 포함하지 않는 것을 의미하지 않는다 또한 아무것도! 귀하의 경우 Cat클래스가 필요로하는 생성자가 name, weight그리고 image, 당신은 성공적으로 모든 고양이가 사람을 가지고 비즈니스 규칙을 캡슐화했습니다. 클래스가 작성된 weight후 를 변경할 수 있으면 Cat캡슐화 된 또 다른 비즈니스 규칙입니다. 이것들은 매우 기본적인 것들이지만, 단지 잘못하지 않는 것이 매우 중요하다는 것을 의미합니다. 이런 식으로, 당신 은 그 잘못을 저지르는 것이 불가능하다는 것을 보장합니다 .

사물

물체는 무언가를합니다. Clean * 객체 를 원하면 "Objects do one "로 변경할 수 있습니다 .

고양이 정보를 인쇄하는 것은 개체의 일입니다. 예를 들어, CatInfoLogger공개 메소드를 사용 하여이 객체를 " " 이라고 부를 수 Log(Cat)있습니다. 이것이 우리가 외부에서 알아야 할 전부입니다.이 객체는 고양이 정보를 기록하기 위해 필요한 정보 Cat입니다.

내부적으로이 개체는 고양이 벌목에 대한 단일 책임 을 수행하는 데 필요한 모든 것에 대한 참조를 갖습니다 . 이 경우, 그것은 단지에 대한 참조입니다 System에 대한 System.out.println있지만, 대부분의 경우, 다른 객체에 대한 개인 참조가 될 것입니다. 인쇄하기 전에 출력 형식을 지정하는 논리가 너무 복잡해지면 CatInfoLogger새 객체에 대한 참조를 얻을 수 있습니다 CatInfoFormatter. 나중에 모든 로그를 파일에 기록해야하는 경우 CatToFileLogger이를 수행 하는 개체를 추가 할 수 있습니다 .

데이터 홀더 대 개체-요약

자, 왜 그렇게 하시겠습니까? 이제 클래스를 변경하면 한 가지만 변경되므로 ( 예제에서 고양이가 기록 되는 방식 ) 객체를 변경하는 경우 특정 작업이 수행되는 방식 만 변경됩니다. 데이터 보유자를 변경하면 보유중인 데이터 및 / 또는 보유 방식 만 변경됩니다.

데이터를 변경하면 작업 수행 방식도 변경되어야 할 수도 있지만, 책임있는 개체를 변경하여 스스로 변경하기 전까지는 변경되지 않습니다.

지나침?

이 솔루션은 약간 과도하게 보일 수 있습니다. 내가 솔직히 보자 : 그것은이다 . 전체 프로그램이 예제만큼 큰 경우 위의 작업을 수행하지 마십시오. 동전 던지기로 제안 된 방법 중 하나를 선택하십시오. 다른 코드 없으면 다른 코드 를 혼동 할 위험 없습니다.

그러나 "심각한"(= 스크립트 또는 2 이상) 소프트웨어는 아마도 이와 같은 구조에서 이익을 얻을만큼 충분히 클 것입니다.


대답

대부분의 클래스를 DTO와 도우미 클래스 [...]로 분리하는 것이 좋거나 반 패턴입니까?

"대부분의 클래스"(추가 자격없이)를 DTO / 데이터 보유자로 바꾸는 것은 실제로 어떤 패턴도 아니기 때문에 다소 패턴이 아니기 때문에 안티 패턴이 아닙니다.

그러나 데이터와 객체를 분리하는 것은 코드를 깨끗하게 유지하는 좋은 방법으로 간주됩니다 *. 때로는 평평한 "무기한"DTO 만 있으면됩니다. 다른 경우에는 데이터 보관 방법을 시행 할 방법이 필요합니다. 프로그램 기능을 데이터와 함께 넣지 마십시오.


* 책 제목과 같은 대문자 C를 사용하는 "청결한"것입니다. 왜냐하면 첫 번째 단락을 기억하십시오. 이것은 하나의 생각 학교에 관한 것이고 다른 것도 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.