타입 코드를 클래스로 교체 (리팩터링 [Fowler])


9

이 전략에는 다음과 같은 것을 대체하는 것이 포함됩니다.

public class Politician
{
    public const int Infidelity = 0;
    public const int Embezzlement = 1;
    public const int FlipFlopping = 2;
    public const int Murder = 3;
    public const int BabyKissing = 4;

    public int MostNotableGrievance { get; set; }
}

와:

public class Politician
{
    public MostNotableGrievance MostNotableGrievance { get; set; }
}

public class MostNotableGrievance
{
    public static readonly MostNotableGrievance Infidelity = new MostNotableGrievance(0);
    public static readonly MostNotableGrievance Embezzlement = new MostNotableGrievance(1);
    public static readonly MostNotableGrievance FlipFlopping = new MostNotableGrievance(2);
    public static readonly MostNotableGrievance Murder = new MostNotableGrievance(3);
    public static readonly MostNotableGrievance BabyKissing = new MostNotableGrievance(4);

    public int Code { get; private set; }

    private MostNotableGrievance(int code)
    {
        Code = code;
    }
}

다음과 같이 유형을 열거하는 것보다 이것이 왜 바람직합니까?

public class Politician
{
    public MostNotableGrievance MostNotableGrievance { get; set; }
}

public enum MostNotableGrievance
{
    Infidelity = 0,
    Embezzlement = 1,
    FlipFlopping = 2,
    Murder = 3,
    BabyKissing = 4
}

유형과 관련된 동작이 없으며 다른 유형의 리팩토링을 사용하는 경우 (예 : '하위 클래스로 유형 코드 바꾸기'+ '다형성으로 조건부 바꾸기').

그러나 저자는 왜이 방법을 찌르는지를 설명합니다 (자바)?

숫자 유형 코드 또는 열거는 C 기반 언어의 일반적인 기능입니다. 기호 이름을 사용하면 읽을 수 있습니다. 문제는 기호 이름이 별명 일뿐입니다. 컴파일러는 여전히 기본 숫자를 봅니다. 컴파일러 유형은 기호 이름이 아닌 숫자 177을 사용하여 확인합니다. 형식 코드를 인수로 사용하는 모든 메소드에는 숫자가 필요하며 기호 이름을 강제로 사용할 것은 없습니다. 이것은 가독성을 줄이고 버그의 원인이 될 수 있습니다.

그러나이 문을 C #에 적용하려고하면이 문은 사실이 아닙니다. 열거는 실제로 클래스로 간주되기 때문에 숫자를 허용하지 않습니다. 따라서 다음 코드는

public class Test
{
    public void Do()
    {
        var temp = new Politician { MostNotableGrievance = 1 };
    }
}

컴파일하지 않습니다. 따라서 C #과 같은 새로운 고급 언어에서는이 리팩토링이 불필요하다고 간주 될 수 있습니까? 아니면 무언가를 고려하고 있지 않습니까?


var temp = new Politician { MostNotableGrievance = MostNotableGrievance.Embezzlement };
Robert Harvey

답변:


6

나는 당신이 거의 자신의 질문에 대답했다고 생각합니다.

두 번째 코드는 형식 안전성을 제공하기 때문에 첫 번째 코드보다 선호됩니다. 첫 번째 조각으로, 비슷한 Fish 열거가 있다면 다음과 같이 말할 수 있습니다.

MostNotableGrievance grievance = Fish.Haddock;

컴파일러는 신경 쓰지 않습니다. Fish.Haddock = 2이면 위의 내용은 정확히

MostNotableGrievance grievance = MostNotableGrievance.FlipFlopping;

그러나 분명히 즉시 읽을 수는 없습니다.

열거 형이 더 좋지 않은 이유는 int와의 암시 적 변환으로 인해 동일한 문제가 발생하기 때문입니다.

그러나 C #에서는 이러한 암시 적 변환이 없으므로 열거 형이 사용하기에 더 좋은 구조입니다. 처음 두 가지 방법 중 하나를 사용하는 경우는 거의 없습니다.


5

값과 관련된 동작이없고 그 함께 저장해야 할 추가 정보 가없고 언어가 정수로의 암시 적 변환을 지원하지 않는 경우 열거 형을 사용합니다. 그것이 그들이 거기있는 것입니다.


1

Effective Java (항목 30, 조회하려는 경우)에서 찾을 수있는 또 다른 예입니다. C #에도 유효합니다.

int 상수를 사용하여 뱀과 개와 같은 다른 동물을 모델링한다고 가정 해보십시오.

int SNAKE_PYTHON=0;
int SNAKE_RATTLE=1;
int SNAKE_COBRA=2;

int DOG_TERRIER=0;
int DOG_PITBULL=1;

이것이 상수이고 다른 클래스로 정의되어 있다고 가정하십시오. 이것은 당신에게 잘 보일 수 있으며 실제로 해결할 수 있습니다. 그러나 다음 코드 줄을 고려하십시오.

snake.setType(DOG_TERRIER);

분명히 이것은 오류입니다. 컴파일러는 불평하지 않고 코드가 실행됩니다. 그러나 당신의 뱀은 개로 변하지 않을 것입니다. 컴파일러는 다음 만 볼 수 있기 때문입니다.

snake.setType(0);

당신의 뱀은 실제로 파이썬입니다 (그리고 테리어가 아닙니다). 이 기능을 유형 안전이라고하며 실제로 예제 코드 인 이유입니다.

var temp = new Politician { MostNotableGrievance = 1 };

컴파일하지 않습니다. MostNotableGrievance는 정수가 아닌 MostNotableGrievance입니다. 열거 형을 사용하면 유형 시스템에서 이것을 표현할 수 있습니다. 그래서 Martin Fowler와 나는 열거가 훌륭하다고 생각합니다.

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