메소드 체인을 통해 컨텍스트를 전달하기위한 패턴


19

이것은 상당히 많은 것으로 보이는 디자인 결정입니다. 컨텍스트 필요로하지 않는 메소드를 통해 컨텍스트를 전달 하는 방법. 정답이 있거나 상황에 따라 달라 집니까?

솔루션이 필요한 샘플 코드

// needs the dependency
function baz(session) {
  session('baz');
}

// doesn't care about the dependency
function bar() {
  baz();
}

// needs the dependency
function foo(session) {
   session('foo')
   bar();
}

// creates the dependency
function start() {
  let session = new Session();
  foo(session);
}

가능한 해결책

  • 스레드 로컬
  • 글로벌
  • 컨텍스트 객체
  • 의존성을 통과시키다
  • 카레 바즈와 의존성을 첫 번째 인수로 설정하여 바에 전달하십시오.
  • 의존성 주입

어디에서 나오는지 예

HTTP 요청 처리

요청 속성 형식의 컨텍스트 객체가 자주 사용됩니다 (expressjs, Java Servlets 또는 .net의 owin 참조).

벌채 반출

Java 로깅 사람들은 종종 글로벌 / 싱글 톤을 사용합니다. 일반적인 log4j / commons logging / java 로깅 패턴을 참조하십시오.

업무

스레드 로컬은 종종 필요하지 않은 모든 메소드에 매개 변수로 전달하지 않아도되도록 일련의 메소드 호출과 연관된 트랜잭션 또는 세션을 유지하는 데 사용됩니다.


보다 의미있는 예를 사용하십시오.
Tulains Córdova

나는 그것이 어디에서 나오는지 몇 가지 예를 추가했습니다.
Jamie McCrindle

3
더 의미있는 예제 코드를 의미했습니다.
Tulains Córdova

답변:


11

유일한 정답은 프로그래밍 패러다임의 관용구에 달려 있다는 것입니다. OO를 사용하는 경우 메소드마다 메소드에 종속성을 전달하는 것은 거의 올바르지 않습니다. OO의 코드 냄새입니다. 사실, OO가 해결하는 문제 중 하나입니다 . 객체 가 컨텍스트를 수정 합니다. OO에서 올바른 하나의 방법 (항상 다른 방법이 있음)은 생성자 또는 속성을 통해 종속성을 제공하는 것입니다. 어떤 제안자는 "종속성 주입"에 대해 언급하고 있으며 이는 완전히 합법적이지만 반드시 필요한 것은 아닙니다. fooand 의 멤버로 사용할 수 있도록 종속성을 제공하십시오 baz.

커링에 대해 언급 했으므로 함수형 프로그래밍이 문제가 아니라고 가정합니다. 이 경우 철학적으로 동등한 객체 컨텍스트는 폐쇄입니다. 다시 한 번 의존성을 수정하여 부양 가족이 사용할 수있는 모든 접근 방식은 정상적으로 작동합니다. 카레는 그러한 접근 방식 중 하나입니다 (그리고 똑똑하게 들립니다). 의존성을 극복하는 다른 방법이 있다는 것을 기억하십시오. 그들 중 일부는 우아하고 일부는 끔찍합니다.

Aspect 지향 프로그래밍을 잊지 마십시오 . 지난 몇 년 동안 호의를 얻지 못한 것으로 보이지만, 주요 목표는 설명하는 문제를 정확하게 해결하는 입니다. 사실, 전형적인 Aspect 예제는 로깅입니다. AOP에서 종속성은 다른 코드가 작성된 후 자동으로 추가됩니다. AOP 사람들은 이것을 " 직조 " 라고 부릅니다 . 공통의 측면은 적절한 장소에서 코드로 짜여져 있습니다. 이를 통해 코드를 쉽게 생각하고 멋지게 만들 수 있지만 새로운 테스트 부담이 추가됩니다. 최종 아티팩트가 올바른지 확인하는 방법이 필요합니다. AOP도 이에 대한 답변을 제공하므로 협박하지 마십시오.


OO 메소드 내에서 매개 변수를 전달하는 것이 코드 냄새라고 주장하는 것은 논란의 여지가 있습니다. 나는 완전히 반대라고 주장한다. 클래스 내에서 믹싱 상태와 기능을 장려하는 것은 OO 패러다임에서 가장 큰 실수 중 하나이며 생성자를 통하지 않고 메소드에 직접 의존성을 주입하여 피하는 것이 잘 설계된 부분의 표시이다 OO 여부에 관계없이 코드
David Arno

3
@DavidArno 나는 다른 패러다임을 사용하고 객체 상태 저장을 끝내는 것이 "OO 패러다임에 의한 가장 큰 실수 중 하나"이고 패러다임을 우회하는 것이 좋습니다. 나는 거의 모든 접근법에 반대하는 것이 없지만 일반적으로 저자가 도구와 싸우는 코드를 싫어합니다. 비공개 상태는 OO의 특징입니다. 이 기능을 피하면 일부 OO의 힘을 잃게됩니다.
Scant Roger

1
@DavidArno 모든 상태이고 기능이없는 클래스는 상태에서 변하지 않는 관계를 적용하기위한 메커니즘이 없습니다. 그러한 클래스는 전혀 OO가 아닙니다.
Kevin Krumwiede

@KevinKrumwiede, 어느 정도까지, 당신은 내 의견에 reducto ad absudium을 적용했지만, 당신의 요점은 여전히 ​​잘 만들어졌습니다. 상태에 대한 불변은 "OO에서 이동"의 중요한 부분입니다. 따라서 기능과 상태의 혼합을 피하면 불변성 (생성자가 설정하고 getter를 통해 액세스하는 캡슐화 된 필드)을 달성하는 데 필요한 상태 객체에 충분한 기능을 허용해야합니다.
David Arno

@ScantRoger, 다른 패러다임, 즉 기능적 패러다임이 채택 될 수 있음에 동의합니다. 흥미롭게도 대부분의 최신 "OO"언어는 점점 더 많은 기능적 기능을 가지고 있으므로 "도구와 싸우지 않고"이러한 언어를 고수하고 기능 패러다임을 채택 할 수 있습니다.
David Arno

10

경우에 bar따라 켜져 baz차례로 필요로 dependency하고 bar요구 dependency도 순서대로 올바르게 사용 baz. 따라서 올바른 접근 방식은 매개 변수를 통해 종속성을 전달 bar하거나 카레 baz를 전달하여 전달하는 것 bar입니다.

첫 번째 방법은 구현하고 읽을 간단하지만 사이의 커플 링을 생성 bar하고 baz. 두 번째 방법은 해당 커플 링을 제거하지만 코드가 덜 명확해질 수 있습니다. 따라서 어떤 방법이 가장 좋을지는 두 기능의 복잡성과 동작에 따라 달라질 수 있습니다. 예를 들어, 부작용이 baz있거나 dependency부작용이있는 경우 테스트 용이성은 솔루션을 선택하는 큰 요인이 될 수 있습니다.

제안하는 다른 모든 옵션은 본질적으로 "해킹"이며 테스트 및 버그를 추적하기 어려운 문제를 일으킬 수 있다고 제안합니다.


1
나는 거의 완전히 동의합니다. 의존성 주입은 또 다른 "해킹"방식 일 수 있습니다.
조나단 반 데 빈

1
@JonathanvandeVeen, dependency매개 변수를 통해 전달하는 것은 의존성 주입입니까?
David Arno

2
@DavidArno 의존성 주입 프레임 워크는 이러한 종류의 의존성을 제거하지 않고 단지 이동시킵니다. 마술은 그들이 시험을 다른 누군가의 문제로 옮기는 곳으로 수업 밖으로 옮기는 것입니다.
Kevin Krumwiede

동의합니다. 의존성 주입은 유효한 솔루션입니다. 사실 그것은 내가 가장 자주 선택하는 것입니다.
Jamie McCrindle

1

철학적으로 말하기

David Arno의 우려에 동의합니다 .

구현 솔루션을 찾고 OP를 읽고 있습니다. 그러나 대답은 디자인을 바꾸는 것입니다 . "패턴"? OO 디자인은 문맥에 관한 것입니다. 가능성이있는 방대한 빈 용지입니다.

기존 코드를 다루는 것은 다른 상황입니다.



나는 '현재와 똑같은 문제를 해결하고 있습니다. 글쎄, 나는 값이 주입 될 수 있도록 수행 된 수백 줄의 코드 copy-n-paste를 수정하고있다.

코드 모듈화

"A 호출 B 호출 C 호출 D ..."대신 600 줄의 중복 코드를 버리고 리팩토링했습니다. "A 호출, 리턴, 호출 B, 리턴, 호출 C ..."가 있습니다. 이제 우리는 그 방법들 중 하나에 만 값을 주입하면됩니다. 방법 E라고합시다.

생성자에 기본 매개 변수를 추가하십시오. 기존 발신자는 변경하지 않습니다. 여기서 "선택 사항"이 작동 단어입니다. 인수가 전달되지 않으면 기본값이 사용됩니다. 그런 다음 리팩터링 된 모듈 식 구조로 변수를 전달하기 위해 한 줄만 변경하십시오. 그것을 사용하는 방법 E의 작은 변화.


폐쇄

프로그래머 스레드- "프로그램이 클로저를 사용하는 이유는 무엇입니까?"

기본적으로 값으로 사용자 정의 된 메소드를 리턴하는 메소드에 값을 주입합니다. 그 맞춤형 방법은 이후에 실행됩니다.

이 기술을 사용하면 서명을 변경하지 않고 기존 방법을 수정할 수 있습니다.


이 접근 방식은 이상하게도 익숙해 보입니다 .

@Snowman, 시간적 커플 링 (링크) 문제에 대한 Roger. 필요한 실행 순서를 캡슐화해야합니다.
radarbob
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.