모델에 "FullName"또는 "FormattedPhoneNumber"와 같은 게터를 넣는 것이 "패턴 냄새"입니까?


13

ASP.NET MVC 앱을 만들고 있는데, 유용하고 편리한 게터처럼 보이는 것을 모델 / 엔터티 클래스에 넣는 습관을 들이고 있습니다.

예를 들면 다음과 같습니다.

public class Member
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string PhoneNumber { get; set; }

    public string FullName
    {
        get { return FirstName + " " + LastName; }
    }

    public string FormattedPhoneNumber
    {
        get { return "(" + PhoneNumber.Substring(0, 3) + ") " + PhoneNumber.Substring(3, 3) + "-" + PhoneNumber.Substring(6); }
    }
}

나는 사람들이 생각 궁금하네요 FullNameFormattedPhoneNumber게터.

앱 전체에서 표준화 된 데이터 형식을 만드는 것이 매우 쉬워지고 반복되는 코드를 많이 저장하는 것처럼 보이지만 데이터 형식은 모델에서 뷰 모델로 매핑 할 때 처리해야하는 요소 일 수 있습니다.

사실, 나는 원래 매핑을 수행하는 서비스 계층에 이러한 데이터 형식을 적용하고 있었지만, 포맷터를 지속적으로 작성하여 여러 곳에서 적용해야하는 부담이되었습니다. 예를 들어, 나는 대부분의보기에서 "성명"을 사용 model.FullName = MappingUtilities.GetFullName(entity.FirstName, entity.LastName);하고, 장소 전체에 같은 것을 입력하는 것이 타이핑하는 것보다 덜 model.FullName = entity.FullName우아해 보였습니다.

따라서 데이터 형식과 관련하여 선을 어디에서 그리는가? 모델에서 데이터 형식을 지정하는 것이 "좋아"입니까, 아니면 "패턴 냄새"입니까?

참고 : 내 모델에는 HTML이 없습니다. 나는 그것을 위해 HTML 도우미를 사용합니다. 나는 데이터 (특히 자주 사용되는 데이터)의 형식을 지정하거나 결합하는 것에 대해 엄격하게 이야기하고 있습니다.


1
이렇게하면 편리 할 수 ​​있습니다. 그러나 그 코드를 국제화 할 필요가 없기를 희망하고기도하십시오.
btilly

@ btilly, 좋은 지적이지만 약 99.99 % 확신하지 않습니다.
devuxer

FullName 및 PhoneNumber에만 해당됩니다. 다른 문화권의 형식이 일치하지 않기 때문에 특별히 질문이 있습니까? 아니면 @DanM은 더 일반적인 질문에 대해 국제화가 잘되지 않는 예제를 단순히 선택 했습니까?
Greg Jackson

@ 그렉 잭슨, 확실히 사다리. ammoQ가 지적했듯이 PhoneNumber아마도 (지금 구현 한) 자체 클래스에 속할 것입니다. 그러나 FullName실제로 질문을 작성하도록 동기를 부여한 사람이었습니다. 그러나 일반적으로 앱 전체에 적용 할 항목에 대해 데이터 형식 / 조합 등을 모델에 넣는 것이 합리적인지 여부에 관심이 있습니다. 아래 답변에서 이것은 반 패턴이 아닌 것처럼 보이지만 신중하게 결정해야합니다.
devuxer

이름에 대한이 특정 형식은 국제화되지 않을 수도 있습니다. 예를 들어 동아시아에서 이름 순서는 서구 세계와 반대입니다. 실제로 이것을 명시 적으로 처리해야합니까? 아마도 그렇지는 않지만 데이터를 형식화 할 때 많은 까다로운 것들이 있다는 것을 명심하십시오.
Greg Jackson

답변:


9

귀하의 예에서, 나는 FullName당신이 주신 모든 이유로 getter를 좋아하지만 FormattedPhoneNumber getter를 좋아하지 않습니다. 그 이유는 다음과 같습니다. 아마 국제 전화 번호 등이 있으면 쉽지 않을 것입니다. 그리고 전화 번호를 형식화하는 논리를의 방법으로 배치 하면 한 번 Member리팩터링 (또는 복사하여 붙여 넣기 ) 해야 할 가능성이 있습니다. 에 대한 형식의 전화 번호가 필요 , 등 너무합니다.InstitutionVendor

편집 : IMO 게터 가있는 PhoneNumber수업을하는 것이 좋습니다 Formatted.


+1 감사합니다. 그러나 실제로 전화 번호 형식 코드를 확장 방법에 넣으면 어떻게됩니까? 그런 다음 모든 모델에서 사용할 수 있으며 리팩토링 또는 복사 / 붙여 넣기가 없습니다. 이 솔루션은 모든보기에 나타나는 모든 전화 번호에 포맷터를 적용하는 것보다 훨씬 덜 반복적입니다.
devuxer

3
이를 위해 확장 방법을 사용하면 "기능적 분해"반 패턴으로 빠르게 이동할 수 있습니다. 확장 방법 ( String클래스의 경우)을 사용하여 String클래스에 전화 번호 형식을 지정하는 방법을 "학습"합니다 . String전화 번호에 대해 아는 것이 실제로 수업 의 책임 입니까? 나는 그렇게 생각하지 않습니다. 이와 같이 사용되는 확장 방법은 구문 지향적 설탕으로, 객체 지향적이지 않은 것을 명확하게 보이게합니다.
user281377

1
좋아, 내가 확장 방법을 말한 것을 잊어라. 내가 유틸리티 메소드 또는 포매터 클래스를 말했다. 단순히 모델 게터가 있거나 다른 곳에서 서식을 지정하는지 여부에 관계없이 리팩토링 / 복사 붙여 넣기가 필요하지 않다고 말하고 있습니다.
devuxer 2016 년

1
그리고 나는 PhoneNumber수업 의 아이디어를 좋아한다 . 나는 PhoneType재산 도 있기 때문에 어쨌든 그렇게 할 계획 이었습니다.
devuxer

PhoneNumber데이터가 기본적으로 있기 때문에 인스턴스 클래스로 사용하는 아이디어가 마음에 들지 않습니다 string. 오히려와 같은 메소드를 가진 정적 클래스 여야합니다 public static string Format(string phoneNumber, PhoneNumberStyle style).
미스터 앤더슨

5

코드를 작성할 때 고려해야 할 사항 : 맞습니까? 읽을 수 있습니까? 효율적입니까? 유지 관리가 가능합니까? @btilly가 언급했듯이 문화 별 형식으로 인해 유지 관리 할 수는 없지만 더 일반적인 질문 인 것 같습니다.

이와 같은 접근자를 사용하면 코드를 더 쉽게 읽을 수 있으며 사용 방법에 따라 코드의 다른 부분이 훨씬 깨끗해질 수 있습니다. 제 생각에는 전혀 냄새가 나지 않습니다. 인쇄하려는 문자열의 형식 지정 접근자가 있으면 냄새가 나기 시작합니다 ( public string FirstLastName; public string FullName; public string FullNameWithMiddleInitial; public string PhoneNumberWithAreaCode; public string PhoneNumberWithoutAreaCode; public string PhoneNumberWithCountryCode;등).

또는 패턴을 사용한다고해서 코드에 "패턴 냄새"가 자동으로 부여되는 것은 아닙니다. 해당 속성을 얻으려면 남용해야합니다.


고마워, 그렉 +1. 모든 조합을 넣는 것에 동의합니다. 데이터를 보는 방법을 표준화하는 가장 깨끗한 방법을 찾으려고 노력하고 있습니다.
devuxer

3

단일 책임 원칙을 위반합니다. 전화 번호 클래스 등을 만들어 보시지 않겠습니까?


좋아, 나는 실제로 그것에 동의하지만 (ammoQ의 답변 아래 토론 참조) FullName수업 도해야 합니까?
devuxer

그렇습니다. 그러나 철자를 "FullName"에서 "FoolName"으로 수정해야합니다. 또는 "PersonalName"은 사람의 이름이며 완전한 이름이 아니기 때문일 수 있습니다.
케빈 클라인

1
정말? 주어진 클래스가 성장할 것으로 예상되지 않는 한 정확히 무엇이 잘못 되었습니까? 성장하더라도 리팩토링하는 것이 얼마나 어려울까요?
Job

@ DanM : 그렇다면 그것은 당신이 요구하는 것입니다. 즉, 그들에게 완전한 법적 이름을 입력하도록 요청하십시오. 이름을 기준으로 정렬하는 경우 실제로 이름의 첫 번째 문자 (다음 두 번째 등)를 기준으로 정렬하므로 (다음, 그 다음 등) 이름이 상관없이 동일하게 정렬됩니다.
매트 엘렌


1

귀하의 예를 들어, 특정 형식을 사용하기에는 너무 큰 거래라고 생각하지 않습니다. 하나 또는 두 개이며 응용 프로그램의 모든 부분이 동일한 형식을 사용합니다.

그 결정이 시작되기 시작하는 곳은 동일한 형식의 데이터 가 다른 형식을 요구하는 여러 곳으로 갈 때 입니다.

그런 일이 생기면 Member수업을 다시 끌어들일 유혹이 있습니다 .

public class Member
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string PhoneNumber { get; set; }  
}

그런 다음 각 대상마다 다른 어댑터를 수행하십시오. 예를 들어, 정보가 CSV 형식으로 필요하다고 가정하십시오.

public static class CSVMemberAdapter
{
    public static string ToCSV(this Member mbr)
    {
         return mbr.Id + "," + mbr.LastName + "," + mbr.FirstName, "," mbr.PhoneNumber;
    }
}

항상 문자열에 쉼표 등이 없도록 데이터를 삭제했다고 가정합니다.

어댑터는 확장 방법 일 필요는 없지만,이 make-believe 경우 적합합니다.


C #을 작성한 이후로 오랜 시간이 지났지 만 toCSV와 같은 메소드를 반복해서 반복해서 쓰는 대신에 이것을 처리 할 수있는 직렬화 클래스가 반드시 있어야합니다. 그리고 여러 번 반복해서 ...
kevin cline

@kevin cline : 각 싱크대에서 필요한 것에 따라 다릅니다. 필요한 모든 것이 직렬화 된 XML이면 충분합니다. 많은 시스템은 그렇지 않습니다. 그렇게 over여러 번해야한다면 디자인에 문제가있는 것입니다.
Peter K.

일반적으로 직렬화 할 클래스가 많이 있습니다. 예제처럼 직접 코딩하는 대신 리플렉션을 통해 대부분의 클래스를 처리 할 수있는 단일 CSV 또는 기타 직렬 변환기를 작성할 수 있어야합니다.
케빈 클라인

@kevin cline : 폭력적으로 동의합니다! 나는 그 질문에 매우 구체적인 것을 쓰고 있었다. 구체적이고 간단한 예는 사물을 더 잘 설명하는 경향이 있습니다.
Peter K.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.