[oop] 메소드 체인-왜 좋은 습관입니까?

메소드 체인 은 다른 메소드에 대해 결과를 호출하기 위해 오브젝트 자체를 리턴하는 오브젝트 메소드의 실습입니다. 이처럼 :

participant.addSchedule(events[1]).addSchedule(events[2]).setStatus('attending').save()

읽을 수있는 코드 또는 “유창한 인터페이스”를 생성하기 때문에 이는 좋은 습관으로 간주됩니다. 그러나 나에게 대신 객체 지향 자체에 의해 암시 된 표기법을 호출하는 것으로 보입니다. 결과 코드는 이전 방법 의 결과 에 대한 작업 수행을 나타내지 않습니다 . 이는 객체 지향 코드가 일반적으로 작동하는 방식입니다.

participant.getSchedule('monday').saveTo('monnday.file')

이 차이는 “결과 객체 호출”의 점 표기법에 대해 두 가지 의미를 생성합니다. 연결의 맥락에서, 위 의 예는 실제로 일정을 저장하려는 의도에도 불구하고 참가자 객체 를 저장하는 것으로 읽습니다. getSchedule에 의해 수신 된 오브젝트.

여기서의 차이점은 호출 된 메소드가 무언가를 반환 해야하는지 여부입니다 (이 경우 체인을 위해 호출 된 객체 자체를 반환합니다). 그러나이 두 경우는 표기법 자체와 구별 할 수 없으며 호출되는 메소드의 의미론과 만 구별됩니다. 메소드 체인을 사용하지 않으면 메소드 호출 이 이전 호출 의 결과 와 관련된 것으로 작동한다는 것을 항상 알 수 있습니다. 체인을 사용하면이 가정이 깨지고 실제 객체가 무엇인지 이해하기 위해 전체 체인을 의미 론적으로 처리해야합니다. 정말이라고합니다. 예를 들면 다음과 같습니다.

participant.attend(event).setNotifications('silent').getSocialStream('twitter').postStatus('Joining '+event.name).follow(event.getSocialId('twitter'))

마지막 두 메소드 호출은 getSocialStream의 결과를 참조하지만 이전의 메소드 호출은 참여자를 참조합니다. 어쩌면 컨텍스트가 변경되는 체인을 실제로 작성하는 것은 좋지 않습니다 (그렇지 않습니까?). 그렇더라도 비슷한 모양의 도트 체인이 실제로 동일한 컨텍스트 내에 있는지 또는 결과에 대해서만 작동하는지 지속적으로 확인해야합니다 .

나에게 메소드 체인이 피상적으로 읽을 수있는 코드를 생성하는 동안 점 표기법의 의미를 오버로드하면 혼란이 더 커질 것 같습니다. 내가 프로그래밍 전문가라고 생각하지 않기 때문에 나는 내 잘못이라고 생각한다. 그래서 : 나는 무엇을 놓치고 있습니까? 어떻게 든 메소드 체인을 잘못 이해합니까? 메소드 체인이 특히 좋은 경우 또는 특히 나쁜 경우가 있습니까?

주석 :이 질문은 질문으로 가려진 의견 진술로 읽을 수 있음을 이해합니다. 그러나 체인이 좋은 습관으로 여겨지는 이유를 이해하고 고유 한 객체 지향 표기법을 위반한다고 생각하면 어디에서 잘못되었는지 이해하고 싶습니다.



답변

나는 이것이 주관적인 것에 동의합니다. 대부분의 경우 메소드 체인을 피하지만 최근에는 그것이 옳은 경우를 발견했습니다 .10 개의 매개 변수와 같은 것을 받아들이고 더 많은 것을 필요로하는 메소드가 있었지만 대부분의 경우 조금. 재정의로 인해 이것은 매우 번거로 웠습니다. 대신 체인 방식을 선택했습니다.

MyObject.Start()
    .SpecifySomeParameter(asdasd)
    .SpecifySomeOtherParameter(asdasd)
    .Execute();

메소드 체인 접근 방식은 선택 사항이지만 코드 작성이 더 쉬워졌습니다 (특히 IntelliSense 사용). 이것은 하나의 고립 된 사례이며 내 코드의 일반적인 관행이 아님을 명심하십시오.

요점은-99 %의 경우 메소드 체인을 사용하지 않고도 아마도 더 잘 할 수 있습니다. 그러나 이것이 가장 좋은 방법 인 1 %가 있습니다.


답변

단지 내 2 센트;

메소드 체인은 디버깅을 까다롭게 만듭니다.-중단 점을 간결한 지점에 둘 수 없으므로 원하는 위치에서 프로그램을 정확하게 일시 중지 할 수 있습니다.-이러한 메소드 중 하나에서 예외가 발생하고 행 번호를 얻는다면 전혀 알 수 없습니다. “체인”의 어떤 방법으로 문제가 발생했는지

나는 항상 매우 짧고 간결한 줄을 쓰는 것이 일반적으로 좋은 습관이라고 생각합니다. 모든 라인은 하나의 메소드 호출 만해야합니다. 더 긴 줄보다 더 많은 줄을 선호하십시오.

편집 : 의견은 메소드 체인과 줄 바꿈이 분리되어 있다고 언급합니다. 사실입니다. 디버거에 따라 명령문 중간에 중단 점을 배치 할 수도 있고 불가능할 수도 있습니다. 가능한 경우에도 중간 변수가있는 별도의 줄을 사용하면 조사 프로세스에서 디버깅 프로세스를 도와주는 훨씬 많은 유연성과 조사 할 수있는 많은 값을 얻을 수 있습니다.


답변

개인적으로 저는 여러 속성 설정 또는 유틸리티 유형 메서드 호출과 같이 원본 객체에서만 작동하는 체인 메서드를 선호합니다.

foo.setHeight(100).setWidth(50).setColor('#ffffff');
foo.moveTo(100,100).highlight();

하나 이상의 체인 메소드가 내 예제에서 foo 이외의 객체를 반환 할 때 사용하지 않습니다. 체인에서 해당 객체에 대해 올바른 API를 사용하는 한 구문 상으로 체인을 연결할 수 있지만, 객체를 변경하면 IMHO가 덜 읽기 쉽고 다른 객체의 API에 유사성이있는 경우 실제로 혼란을 줄 수 있습니다. 당신이 마지막에 정말 일반적인 메서드 호출을 할 경우 ( .toString(), .print(), 무엇이든) 어떤 객체는 결국에 작용하는거야? 코드를 우연히 읽는 사람은 원래 참조가 아니라 체인에서 암시 적으로 반환되는 객체라는 것을 알지 못할 수 있습니다.

다른 객체를 연결하면 예기치 않은 null 오류가 발생할 수 있습니다. 내 예제에서 foo 가 유효 하다고 가정하면 모든 메소드 호출은 “안전”합니다 (예 : foo에 유효). OP의 예에서 :

participant.getSchedule('monday').saveTo('monnday.file')

… getSchedule이 실제로 null이 아닌 유효한 일정 객체를 반환한다는 보장은 없습니다 (코드를보고있는 외부 개발자로서). 또한 많은 IDE가 디버그 할 때 메소드 호출을 검사 할 수있는 객체로 평가하지 않기 때문에이 스타일의 코드를 디버깅하는 것이 훨씬 어렵습니다. IMO, 디버깅 목적으로 검사하기 위해 객체가 필요할 때마다 명시 적 변수로 사용하는 것이 좋습니다.


답변

Martin Fowler는 여기서 좋은 토론을합니다.

메소드 체인

사용시기

Method Chaining은 내부 DSL의 가독성을 크게 향상시켜 결과적으로 일부 DSL의 내부 동의어가되었습니다. 그러나 메소드 체인은 다른 기능 조합과 함께 사용할 때 가장 좋습니다.

메소드 체인은 특히 parent :: = (this | that) *와 같은 문법에 효과적입니다. 다른 방법을 사용하면 다음에 어떤 인수가 올지 알 수있는 읽기 쉬운 방법을 제공합니다. 마찬가지로 메소드 인수를 사용하여 선택적 인수를 쉽게 건너 뛸 수 있습니다. parent :: = first second와 같은 필수 절 목록은 기본 인터페이스에서는 잘 작동하지 않지만 점진적 인터페이스를 사용하면 제대로 지원 될 수 있습니다. 대부분의 경우 그 경우 중첩 기능을 선호합니다.

Method Chaining의 가장 큰 문제는 마무리 문제입니다. 해결 방법이 있지만 일반적 으로이 문제가 발생하면 중첩 함수를 사용하는 것이 좋습니다. 컨텍스트 변수로 혼란에 빠지면 중첩 함수를 사용하는 것이 좋습니다.


답변

내 의견으로는, 메소드 체인은 약간의 참신함입니다. 물론, 그것은 시원해 보이지만 실제 이점은 보이지 않습니다.

어때:

someList.addObject("str1").addObject("str2").addObject("str3")

보다 나은 것 :

someList.addObject("str1")
someList.addObject("str2")
someList.addObject("str3")

addObject ()가 새 객체를 반환하는 경우는 예외입니다.이 경우 연결되지 않은 코드는 다음과 같이 조금 더 성 가실 수 있습니다.

someList = someList.addObject("str1")
someList = someList.addObject("str2")
someList = someList.addObject("str3")


답변

예상보다 많은 객체에 의존 할 수 있으므로 위험하므로 다른 클래스의 인스턴스를 반환합니다.

예를 들어 보겠습니다.

foodStore는 소유 한 많은 식품점으로 구성된 개체입니다. foodstore.getLocalStore ()는 가장 가까운 상점에 대한 정보를 보유한 객체를 매개 변수에 반환합니다. getPriceforProduct (anything)는 해당 객체의 메소드입니다.

따라서 foodStore.getLocalStore (parameters) .getPriceforProduct (anything)를 호출하면

FoodStore뿐만 아니라 LocalStore에도 의존하고 있습니다.

getPriceforProduct (anything)가 변경되면 FoodStore뿐만 아니라 chained 메소드를 호출 한 클래스도 변경해야합니다.

클래스 간 느슨한 결합을 항상 목표로해야합니다.

즉, 루비를 프로그래밍 할 때 개인적으로 연결하는 것을 좋아합니다.


답변

많은 사람들이 가독성 문제를 염두에 두지 않고 메서드 체인을 편의의 형태로 사용합니다. 메소드 체인은 동일한 오브젝트에서 동일한 조치를 수행하는 경우 허용되지만 코드 작성이 적을뿐 아니라 실제로 가독성을 향상시키는 경우에만 허용됩니다.

불행히도 많은 사람들이 질문에 주어진 예에 따라 메소드 체인을 사용합니다. 그들이하는 동안 수 있습니다 여전히 읽을 할, 그들은 불행하게도 여러 클래스 사이의 높은 커플 링을 일으키는, 그래서 그것은 바람직하지 않습니다.