객체를 제대로 인스턴스화하지 못하는 생성자를 작성하는 방법


12

때로는 실패 할 수있는 생성자를 작성해야합니다. 예를 들어 파일 경로를 사용하여 객체를 인스턴스화하고 싶다고 가정 해보십시오.

obj = new Object("/home/user/foo_file")

경로가 적절한 파일을 가리키는 한 모든 것이 좋습니다. 그러나 문자열이 유효한 경로가 아닌 경우 문제가 발생합니다. 그러나 어떻게?

당신은 할 수 있습니다 :

  1. 예외를 던지다
  2. null 객체 반환 (프로그래밍 언어에서 생성자가 값을 반환 할 수있는 경우)
  3. 경로가 올바르게 설정되지 않았 음을 나타내는 플래그와 함께 유효한 객체를 반환합니다 (ugh).
  4. 다른 사람?

다양한 프로그래밍 언어의 "모범 사례"가이를 다르게 구현한다고 가정합니다. 예를 들어 ObjC는 (2)를 선호한다고 생각합니다. 그러나 (2) 생성자가 반환 유형으로 void를 가져야하는 C ++에서는 구현할 수 없습니다. 이 경우 (1)이 사용됩니다.

선택한 프로그래밍 언어로이 문제를 어떻게 처리하고 그 이유를 설명 할 수 있습니까?


1
Java의 예외는 이것을 처리하는 한 가지 방법입니다.
Mahmoud Hossam

C ++ 생성자는 반환하지 않고 void개체를 반환합니다.
gablin

6
@gablin : 사실, 그것은 사실도 엄격하지 않습니다. new호출 operator new하여 메모리를 할당 한 다음 생성자를 채우십시오. 생성자는 아무것도 반환하지 않으며 new에서 얻은 포인터를 반환합니다 operator new. "아무것도 돌려주지 않는다"는 것이 "반품"을 의미하는지 void는 이해하기 쉽다.
Jon Purdy

@ 존 퍼디 : 흠, 합리적인 것 같습니다. 잘 했어
gablin

답변:


8

더러운 작업을 수행하기 위해 생성자에 의존하는 것은 결코 좋지 않습니다. 게다가, 명시적인 문서가 명시되어 있지 않은 한 (그리고 클래스의 사용자가 읽거나 말하지 않았다면) 생성자에서 작업을 수행할지 여부는 다른 프로그래머에게 명확하지 않습니다.

예를 들어 (C #에서) :

public Sprite
{
    public Sprite(string filename)
    {
    }
}

사용자가 파일을 바로로드하지 않으려면 어떻게됩니까? 파일을 주문형 캐싱하려면 어떻게해야합니까? 그들은 할 수 없습니다. bool loadFile생성자에 인수 를 넣는 것을 생각할 수도 있지만, 여전히Load() 파일을로드 하는 메소드가 필요 하므로이 방법 이 복잡 합니다.

현재 시나리오를 고려할 때, 클래스 사용자는이를 위해보다 유연하고 명확 해집니다.

Sprite sprite = new Sprite();
sprite.Load("mario.png");

또는 대안으로 (자원과 같은 것) :

Sprite sprite = new Sprite();
sprite.Source = "mario.png";
sprite.Cache();

// On demand caching of file contents.
public void Cache()
{
     if (image == null)
     {
         try
         {
             image = new Image.FromFile(Source);
         }
         catch(...)
         {
         }
     }
}

귀하의 경우로드 (..)가 실패하면 완전히 쓸모없는 객체가 있습니다. 나는 아무 스프라이트없이 스프라이트를 원할지 모르겠다 ... 그러나 질문은 실제 질문보다 holywar 주제처럼 보인다 :)
avtomaton

7

Java에서는 예외를 사용하거나 팩토리 패턴을 사용하여 널을 리턴 할 수 있습니다.

스칼라에서는 팩토리 메소드에서 Option [Foo]를 반환 할 수 있습니다. Java에서도 작동하지만 더 번거로울 것입니다.


.NET 언어에서 예외 또는 팩토리 사용
Beth Whitezel

3

예외를 던지십시오.

당신이 그것을 반환 할 수있는 경우 null을 확인해야합니다 (확인되지 ​​않습니다)

이것이 확인 된 예외에 대한 것입니다. 당신은 그것이 실패 할 수 있다는 것을 알고 있습니다. 발신자가이 문제를 처리해야합니다.


3

에서 C ++ , 생성자는 클래스의 / 초기화 구성원을 만드는 데 사용됩니다.

이 질문에 대한 정답은 없습니다 . 그러나 지금까지 내가 관찰 한 것은 대부분이 클라이언트를 처리하는 방법을 선택하는 클라이언트 (또는 API를 사용하려는 사람)라는 것입니다.

때때로 그들은 모든 자원 생성자의 오브젝트 힘 필요를 할당하도록 요청할 수 있습니다 던져 확인 창조는 항상 성공 뭔가 (객체의 생성을 중단) 실패 할 경우 예외를, 또는 생성자에 그 어느 것도하지 않는다, 및 확인 , 일부 구성원 기능에 대해 이러한 작업을 남겨 둡니다.

비헤이비어를 선택하는 것이 당신의 몫이라면, 예외는 에러를 처리하는 기본 C ++ 방식 이며 가능하면 에러 를 사용해야합니다.


1

매개 변수가 없거나 절대 실패하지 않는 매개 변수만으로 개체를 인스턴스화 한 다음 안전하게 예외를 throw하거나 원하는 작업을 수행 할 수있는 초기화 함수 또는 메서드를 사용할 수 있습니다.


6
추가 초기화가 필요한 사용할 수없는 객체를 반환하는 것이 최악의 선택이라고 생각합니다. 이제 클래스가 사용될 때마다 또는 새로운 메소드를 고려할 때마다 복사해야하는 여러 줄 조각이 있습니다. 생성자가 모든 작업을 수행하고 객체를 생성 할 수없는 경우 예외를 발생시킬 수도 있습니다.
케빈 클라인

2
@kevin : 개체에 따라 다릅니다. 실패는 외부 리소스로 인한 것일 수 있으므로 엔티티는 의도 (예 : 파일 이름)를 등록하려고하지만 완전히 초기화하려는 반복 시도는 허용 할 수 있습니다. 값 객체의 경우 아마도 기본 오류를 캡처 할 수있는 오류를보고하여 (포장?) 예외를 던질 것입니다.
Dave

-4

생성자에서 클래스 또는 목록을 초기화하지 않는 것이 좋습니다. 필요할 때마다 수업이나 목록을 초기화하십시오. 예 :

public class Test
{
    List<Employee> test = null;
}

이러지마

public class Test
{
    List<Employee> test = null;

    public Test()
    {
        test = new List<Employee>();
    }
}

대신 필요할 때 초기화하십시오.

public class Test
{
    List<Employee> emp = null;

    public Test()
    { 
    }

    public void SomeFunction()
    {
         emp = new List<Employee>();
    }
}

1
이것은 좋지 않은 조언입니다. 오브젝트가 유효하지 않은 상태가되도록 허용해서는 안됩니다. 그게 생성자입니다. 복잡한 논리가 필요한 경우 팩토리 패턴을 사용하십시오.
AlexFoxGill

1
생성자는 클래스 불변량을 설정하기 위해 존재하며 샘플 코드는 그것을 주장하는 데 도움이되지 않습니다.
Niall
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.