우리는 생성자없이 살 수 있습니까? 어떤 이유로 든 모든 객체가

어떤 이유로 든 모든 객체가 $ obj = CLASS :: getInstance () 방식으로 생성되었다고 가정 해 봅시다. 그런 다음 setter를 사용하여 종속성을 주입하고 $ obj-> initInstance ()를 사용하여 초기화 시작을 수행합니다. 생성자를 전혀 사용하지 않으면 해결할 수없는 실제 문제 나 상황이 있습니까?

추신 :이 방법으로 객체를 생성하는 이유는 일부 규칙에 따라 getInstance () 내부의 클래스를 바꿀 수 있기 때문입니다.

PHP에서 일하고 있습니다.



답변

나는 이것이 당신의 디자인 공간을 심각하게 방해한다고 말하고 싶습니다.

생성자는 전달 된 매개 변수를 초기화하고 유효성을 검증하기에 좋은 장소입니다. 더 이상이를 사용할 수없는 경우, 초기화, 상태 처리 (또는 “손상된”오브젝트의 생성자를 거부하는 것)가 훨씬 어렵고 부분적으로 불가능 해집니다.

예를 들어, 모든 Foo객체에 필요한 Frobnicator경우 생성자 Frobnicator가 null이 아닌 경우 생성자를 확인할 수 있습니다 . 생성자를 제거하면 확인하기가 더 어려워집니다. 그것이 사용될 모든 지점에서 점검합니까? 에서 init()방법 (효과적으로 생성자 메소드 외부화)? 절대 확인하지 않고 최선을 다 하시겠습니까?

여전히 모든 것을 구현할 수는 있지만 (결국 아직 완료되지 않은 경우도 있지만) 수행하기가 훨씬 더 어려울 수 있습니다.

개인적으로 Dependency Injection / Inversion of Control을 살펴볼 것을 제안 합니다 . 이러한 기술은 또한 구체적인 구현 클래스를 전환 할 수 있지만 생성자를 작성 / 사용하는 것을 막지는 않습니다.


답변

생성자에게 2 가지 장점 :

생성자는 객체의 구성 단계를 원자 적으로 수행 할 수 있습니다.

생성자를 피하고 모든 것을 위해 setter를 사용할 수 있지만 Joachim Sauer가 제안한 필수 속성은 어떻습니까? 생성자를 사용하면 객체는 자신의 생성 논리를 소유하여 해당 클래스의 유효하지 않은 인스턴스가 없는지 확인합니다 .

인스턴스를 만들 때 Foo3 개의 속성을 설정해야하는 경우 생성자는 3 개 모두에 대한 참조를 가져 와서 유효성을 검사하고 유효하지 않은 경우 예외를 throw 할 수 있습니다.

캡슐화

세터에만 의존함으로써 객체를 올바르게 구축하는 것은 소비자의 부담입니다. 유효한 여러 속성 조합이있을 수 있습니다.

예를 들어, 모든 Foo인스턴스의 인스턴스 중 하나를 필요로 Bar재산 bar또는 인스턴스 BarFinder로 속성을 barFinder. 둘 중 하나를 사용할 수 있습니다. 유효한 모든 매개 변수 집합에 대한 생성자를 만들고 이러한 방식으로 규칙을 적용 할 수 있습니다.

객체의 논리와 의미는 객체 자체 내에 있습니다. 캡슐화가 좋습니다.


답변

예, 생성자없이 살 수 있습니다.

물론, 많은 중복 보일러 판 코드가 생길 수 있습니다. 또한 응용 프로그램의 규모가 크면 해당 응용 프로그램에서 상용구 코드를 일관되게 사용하지 않을 때 문제의 원인을 찾는 데 많은 시간이 소요될 수 있습니다.

그러나 아닙니다. 자신의 생성자를 엄격하게 ‘필요’하지는 않습니다. 물론 클래스와 객체를 엄격하게 ‘필요’하지는 않습니다.

이제 목표가 객체 생성에 일종의 팩토리 패턴을 사용하는 것이면 객체를 초기화 할 때 생성자를 사용하는 것만으로는 상호 배타적이지 않습니다.


답변

생성자를 사용하면 유효하지 않은 객체가없는 것을 쉽게 만들 수 있다는 장점이 있습니다.

생성자는 객체의 모든 멤버 변수를 유효한 상태로 설정할 수있는 기회를 제공합니다. 그런 다음 뮤 테이터 메소드가 오브젝트를 유효하지 않은 상태로 변경할 수 없는지 확인하면 유효하지 않은 오브젝트가 없으므로 많은 버그를 피할 수 있습니다.

그러나 새 객체가 유효하지 않은 상태로 생성되고 사용할 수있는 유효한 상태로 전환하기 위해 일부 세터를 호출해야하는 경우, 클래스 소비자가 이러한 세터를 호출하거나 잘못 호출하는 것을 잊어 버릴 위험이 있습니다. 당신은 잘못된 개체로 끝납니다.

해결 방법은 팩토리 메소드를 통해서만 오브젝트를 작성하여 호출자에게 리턴하기 전에 오브젝트가 작성하는지 유효성을 점검합니다.


답변

$ obj = CLASS :: getInstance (). 그런 다음 setter를 사용하여 종속성을 주입하고 $ obj-> initInstance ()를 사용하여 초기화 시작을 수행합니다.

나는 당신이 필요 이상으로 이것을 어렵게 만들고 있다고 생각합니다. 우리는 생성자를 통해 종속성을 잘 주입 할 수 있습니다-생성자가 많으면 사전과 같은 구조를 사용하여 사용하려는 것을 지정할 수 있습니다.

$obj = new CLASS(array(
    'Frobnicator' => (),
    'Foonicator' => (),
));

그리고 생성자 내에서 다음과 같이 일관성을 보장 할 수 있습니다.

if (!array_key_exists('Frobnicator', $args)) {
    throw new Exception('Frobnicator required');
}
if (!array_key_exists('Foonicator', $args)) {
    $args['Foonicator'] = new DefaultFoonicator();
}

$args 그런 다음 필요에 따라 개인 구성원을 설정하는 데 사용할 수 있습니다.

그렇게 생성자 내에서 완전히 수행되면 $obj질문에 설명 된 시스템에서와 같이 존재하지만 초기화되지 않은 중간 상태는 절대 존재하지 않습니다. 객체가 항상 올바르게 사용되는 것을 보장 할 수 없기 때문에 이러한 중간 상태를 피하는 것이 좋습니다.


답변

나는 실제로 비슷한 것들에 대해 생각하고있었습니다.

내가 물었던 질문은 “어떤 생성자가 하는가, 다르게 할 수 있는가?”였습니다. 나는 그 결론에 도달했다.

  • 일부 속성이 초기화되도록합니다. 매개 변수로 승인하고 설정합니다. 그러나 이것은 컴파일러에 의해 쉽게 시행 될 수 있습니다. 필드 또는 속성에 “필수”로 주석을 달기 만하면 컴파일러는 인스턴스가 생성되는 동안 모든 것이 올바르게 설정되었는지 확인합니다. 인스턴스를 생성하는 호출은 아마도 동일 할 것입니다. 생성자 메서드는 없습니다.

  • 속성이 유효한지 확인하십시오. 이것은 assert 조건에 의해 쉽게 달성 될 수 있습니다. 다시 한 번 올바른 조건으로 속성에 주석을 달았습니다. 일부 언어는 이미이 작업을 수행합니다.

  • 좀 더 복잡한 구성 논리. 현대적인 패턴은 생성자에서 권장하지 않지만 특수 팩토리 메소드 또는 클래스를 사용하도록 제안합니다. 따라서이 경우 생성자의 사용은 최소화됩니다.

따라서 귀하의 질문에 대답하십시오 : 예, 가능합니다. 그러나 언어 디자인에 큰 변화가 필요합니다.

그리고 방금 내 대답이 꽤 OT라는 것을 알았습니다.


답변

예, 생성자를 사용하지 않고도 거의 모든 작업을 수행 할 수 있지만 이는 객체 지향 프로그래밍 언어의 이점을 분명히 제공합니다.

현대 언어 (내가 프로그래밍 한 C #에 대해 이야기 할 것 입니다)에서는 생성자 에서만 실행할 수있는 코드 부분을 제한 할 수 있습니다 . 서투른 실수를 피할 수있는 덕분입니다. 그러한 것 중 하나는 읽기 전용 수정 자입니다.

public class A {
    readonly string rostring;

    public A(string arg) {
        rostring = arg;
    }

    public static A CreateInstance(string arg) {
        var result = new A();
        A.rostring = arg;  // < because of this the code won't compile!
        return result;
    }
}

으로 요아킴 사우어 권장 사용하는 이전 대신 Factory디자인 후두둑을 읽어 Dependency Injection. Mark Seemann의 .NET에서 Dependency Injection을 읽는 것이 좋습니다 .