30 개의 매개 변수를 사용하는 메서드가 있습니다. 매개 변수를 가져 와서 하나의 클래스에 넣어서 하나의 매개 변수 (클래스)를 메소드에 전달할 수있었습니다. 리팩토링의 경우 모든 매개 변수가 포함되어 있더라도 모든 매개 변수를 캡슐화하는 개체를 전달하는 것이 완벽하게 괜찮습니까?
30 개의 매개 변수를 사용하는 메서드가 있습니다. 매개 변수를 가져 와서 하나의 클래스에 넣어서 하나의 매개 변수 (클래스)를 메소드에 전달할 수있었습니다. 리팩토링의 경우 모든 매개 변수가 포함되어 있더라도 모든 매개 변수를 캡슐화하는 개체를 전달하는 것이 완벽하게 괜찮습니까?
답변:
좋은 생각입니다. 예를 들어 일반적으로 WCF에서 데이터 계약이 수행되는 방식입니다.
이 모델의 한 가지 장점은 새 매개 변수를 추가하면 클래스의 소비자가 매개 변수를 추가하기 위해 변경할 필요가 없다는 것입니다.
David Heffernan이 언급했듯이 코드를 자체 문서화하는 데 도움이 될 수 있습니다.
FrobRequest frobRequest = new FrobRequest
{
FrobTarget = "Joe",
Url = new Uri("http://example.com"),
Count = 42,
};
FrobResult frobResult = Frob(frobRequest);
여기에있는 다른 답변은 클래스의 인스턴스를 전달하는 것이 30 개의 매개 변수를 전달하는 것보다 낫다는 것을 올바르게 지적하고 있지만, 많은 수의 매개 변수가 근본적인 문제의 증상 일 수 있음을 유의하십시오.
예를 들어, 정적 메서드는 매개 변수 수가 증가하는 경우가 많습니다. 그 이유는 모두 인스턴스 메서드 여야했기 때문이며 해당 클래스의 인스턴스에서 더 쉽게 유지 관리 할 수있는 많은 정보를 전달하고 있기 때문입니다.
또는 매개 변수를 더 높은 추상화 수준의 개체로 그룹화하는 방법을 찾습니다. 관련되지 않은 여러 매개 변수를 단일 클래스로 덤프하는 것은 최후의 수단 IMO입니다.
매개 변수가 너무 많습니까?를 참조하십시오 . 이것에 대한 더 많은 아이디어를 위해.
좋은 시작입니다. 하지만 이제 새로운 클래스가 생겼으므로 코드를 뒤집어 보는 것을 고려하십시오. 해당 클래스를 매개 변수로 사용하는 메서드를 새 클래스로 이동합니다 (물론 원래 클래스의 인스턴스를 매개 변수로 전달). 이제 클래스에서 혼자 큰 방법을 얻었으며 더 작고 관리하기 쉽고 테스트 가능한 방법으로 분리하는 것이 더 쉬울 것입니다. 이러한 메서드 중 일부는 원래 클래스로 돌아갈 수 있지만 공정한 청크는 아마도 새 클래스에 남아있을 것입니다. 매개 변수 개체 소개를 넘어 메서드를 메서드 개체 로 바꾸기 로 이동했습니다 .
30 개의 매개 변수가있는 메소드가 있다는 것은 메소드가 너무 길고 복잡하다는 매우 강력한 신호입니다. 디버깅하기가 너무 어렵고 테스트하기가 너무 어렵습니다. 그래서 당신은 그것에 대해 뭔가를해야하고 Introduce Parameter Object는 시작하기에 좋은 곳입니다.
매개 변수 객체로 리팩토링하는 것이 그 자체로 나쁜 생각은 아니지만 다른 곳에서 제공되는 30 개의 데이터가 필요한 클래스가 여전히 코드 냄새가 될 수 있다는 문제를 숨기는 데 사용해서는 안됩니다. Introduce Parameter Object 리팩토링은 해당 절차의 끝이 아니라 광범위한 리팩토링 프로세스의 한 단계로 간주되어야합니다.
실제로 해결되지 않는 문제 중 하나는 Feature Envy입니다. Parameter Object가 전달되는 클래스가 다른 클래스의 데이터에 너무 관심이 있다는 사실이 해당 데이터에 대해 작동하는 메서드가 데이터가있는 곳으로 이동해야한다는 것을 의미하지 않습니까? 함께 속하는 메서드와 데이터의 클러스터를 식별하고 클래스로 그룹화하여 캡슐화를 늘리고 코드를 더 유연하게 만드는 것이 정말 좋습니다.
동작과 데이터를 분리하는 작업을 여러 번 반복 한 후 별도의 단위로 작동하는 클래스가 더 이상 존재하지 않는다는 사실을 발견해야합니다. 이는 코드를 더 유연하게 만들 수 있기 때문에 항상 더 나은 최종 결과입니다.
그것은 훌륭한 아이디어이며 문제에 대한 매우 일반적인 해결책입니다. 매개 변수가 2 개 또는 3 개 이상인 메서드는 기하 급수적으로 더 어려워지고 이해하기가 더 어려워집니다.
이 모든 것을 단일 클래스로 캡슐화하면 코드가 훨씬 더 명확 해집니다. 속성에 이름이 있기 때문에 다음과 같이 자체 문서화 코드를 작성할 수 있습니다.
params.height = 42;
params.width = 666;
obj.doSomething(params);
당연히 많은 매개 변수가있을 때 위치 식별을 기반으로 한 대안은 단순히 끔찍합니다.
또 다른 이점은 모든 호출 사이트에서 변경을 강제하지 않고도 인터페이스 계약에 추가 매개 변수를 추가 할 수 있다는 것입니다. 그러나 이것은 보이는 것처럼 항상 사소한 것은 아닙니다. 다른 호출 사이트에 새 매개 변수에 대해 다른 값이 필요한 경우 매개 변수 기반 접근 방식보다이를 추적하기가 더 어렵습니다. 매개 변수 기반 접근 방식에서 새 매개 변수를 추가하면 각 호출 사이트에서 새 매개 변수를 제공하도록 강제로 변경되며 컴파일러가 모든 매개 변수를 찾는 작업을 수행하도록 할 수 있습니다.
Martin Fowler는 그의 저서 Refactoring 에서이 Introduce Parameter Object 라고 부릅니다 . 그 인용으로 그것을 나쁜 생각이라고 부르는 사람은 거의 없습니다.
30 개의 매개 변수는 엉망입니다. 속성을 가진 클래스를 갖는 것이 훨씬 더 예쁘다고 생각합니다. 동일한 범주에 맞는 매개 변수 그룹에 대해 여러 "매개 변수 클래스"를 만들 수도 있습니다.
클래스 대신 구조를 사용할 수도 있습니다.
그러나 당신이하려는 것은 매우 일반적이고 훌륭한 아이디어입니다!
리팩토링 여부에 관계없이 Plain Old Data 클래스 를 사용하는 것이 합리적 일 수 있습니다 . 왜 그렇게 생각하지 않았는지 궁금합니다.
아마도 C # 4.0의 선택적 매개 변수와 명명 된 매개 변수가 이것에 대한 좋은 대안일까요?
어쨌든, 당신이 설명하는 방법은 프로그램 동작을 추상화하는데도 좋습니다. 예를 들어 SaveImage(ImageSaveParameters saveParams)
인터페이스에 하나의 표준 기능이있을 수 있으며 , 인터페이스 ImageSaveParameters
이기도하며 이미지 형식에 따라 추가 매개 변수를 가질 수 있습니다. 예를 들어 JpegSaveParameters
이 Quality
동안 -property을 PngSaveParameters
A가 들어BitDepth
-property을.
이것은 Paint.NET의 저장 저장 대화 상자가 수행하는 방법이므로 매우 실제적인 예입니다.
여기에 많은 훌륭한 답변이 있습니다. 2 센트를 더하고 싶습니다.
매개 변수 개체는 좋은 시작입니다. 하지만 할 수있는 일이 더 많습니다. 다음을 고려하십시오 (루비 예제).
/ 1 / 단순히 모든 매개 변수를 그룹화하는 대신 의미있는 매개 변수 그룹화가 있는지 확인하십시오. 둘 이상의 매개 변수 오브젝트가 필요할 수 있습니다.
def display_line(startPoint, endPoint, option1, option2)
될 수 있습니다
def display_line(line, display_options)
/ 2 / 매개 변수 개체는 원래 매개 변수 수보다 속성 수가 적을 수 있습니다.
def double_click?(cursor_location1, control1, cursor_location2, control2)
될 수 있습니다
def double_click?(first_click_info, second_click_info)
# MouseClickInfo being the parameter object type
# having cursor_location and control_at_click as properties
이러한 사용은 이러한 매개 변수 개체에 의미있는 동작을 추가 할 가능성을 발견하는 데 도움이됩니다. 당신은 그들이 당신의 편안함을 위해 초기 데이터 클래스 냄새를 더 빨리 털어내는 것을 발견 할 것 입니다. :-)