모델에 "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); }
    }
}

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

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

사실, 나는 원래 매핑을 수행하는 서비스 계층에 이러한 데이터 형식을 적용하고 있었지만, 포맷터를 지속적으로 작성하여 여러 곳에서 적용해야하는 부담이되었습니다. 예를 들어, 나는 대부분의보기에서 "성명"을 사용 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.