“함수와 데이터 간의 긴밀한 결합”이 나쁜 이유는 무엇입니까? 지정하거나 폴더에 파일을 고정시키는 것처럼

나는이 인용문을 ” The Clojure의 기쁨 “에서 찾을 수있다 . 32, 그러나 누군가 지난 주 저녁에 나에게 똑같은 것을 말했고 나는 다른 곳에서도 들었습니다.

[A] 객체 지향 프로그래밍의 단점은 함수와 데이터 사이의 긴밀한 연결입니다.

응용 프로그램에서 불필요한 결합이 나쁜 이유를 이해합니다. 또한 객체 지향 프로그래밍에서도 가변 상태와 상속을 피해야한다는 것이 편안합니다. 그러나 클래스에서 함수를 고수하는 것이 본질적으로 나쁜 이유를 알지 못합니다.

클래스에 함수를 추가하면 Gmail에서 메일에 태그를 지정하거나 폴더에 파일을 고정시키는 것처럼 보입니다. 다시 찾는 데 도움이되는 조직 기술입니다. 당신은 몇 가지 기준을 고른 다음에 같은 것을 합치십시오. OOP 이전에, 우리 프로그램은 파일에 많은 방법이있었습니다. 내 말은, 당신은 어딘가에 기능을 넣어야한다는 것을 의미합니다. 왜 정리하지 않습니까?

이것이 유형에 대한 가려진 공격이라면 입력 및 출력 유형을 함수로 제한하는 것이 잘못되었다고 말하는 이유는 무엇입니까? 나는 그것에 동의 할 수 있는지 확실하지 않지만 적어도 찬반론과 안전 유형 논쟁에 익숙합니다. 이것은 주로 별개의 문제처럼 들립니다.

물론, 때때로 사람들은 그것을 잘못 이해하고 잘못된 수업에 기능을 추가합니다. 그러나 다른 실수와 비교할 때 이것은 약간의 불편 함처럼 보입니다.

따라서 Clojure에는 네임 스페이스가 있습니다. OOP의 클래스에서 함수를 고수하는 것은 Clojure의 네임 스페이스에서 함수를 고수하는 것과 어떻게 다르며 왜 그렇게 나쁩니 까? 클래스의 함수가 반드시 해당 클래스의 멤버에서만 작동하는 것은 아닙니다. java.lang.StringBuilder를보십시오-모든 참조 유형 또는 자동 상자를 통해 모든 유형에서 작동합니다.

PS이 인용문은 내가 읽지 않은 책을 참조한다 : Leda : Timothy Budd, 1995의 Multiparadigm Programming .



답변

이론적으로 함수 데이터 결합이 느슨하면 동일한 데이터를 처리하기 위해 더 많은 함수를 쉽게 추가 할 수 있습니다. 단점은 데이터 구조 자체를 변경하기가 더 어렵 기 때문에 실제로 잘 설계된 기능 코드와 잘 설계된 OOP 코드는 매우 유사한 수준의 커플 링을 갖기 때문입니다.

데이터 구조의 예로 DAG (directed acyclic graph)를 사용하십시오. 함수형 프로그래밍에서는 여전히 반복하지 않기 위해 추상화가 필요하므로 노드와 에지를 추가 및 삭제하고 지정된 노드에서 도달 가능한 노드를 찾고 토폴로지 정렬을 만드는 기능이있는 모듈을 만들어야합니다. 컴파일러가 데이터를 적용하지 않더라도 효과적으로 데이터에 밀접하게 연결됩니다. 어려운 방법으로 노드를 추가 할 수 있지만 왜 원하는가? 하나의 모듈 내에서 응집력은 시스템 전체에서 긴밀한 결합을 방지합니다.

반대로 OOP 측에서는 기본 DAG 작업 이외의 기능은 별도의 “보기”클래스에서 수행되며 DAG 개체는 매개 변수로 전달됩니다. DAG 데이터에서 작동하는 뷰를 원하는만큼 추가하여 기능 프로그램에서와 동일한 수준의 기능 데이터 분리를 생성 할 수 있습니다. 컴파일러는 모든 것을 하나의 클래스로 만들지 못하게하지만 동료는 그렇게합니다.

프로그래밍 패러다임을 변경해도 추상화, 응집력 및 결합에 대한 모범 사례는 변경되지 않으며 컴파일러가 적용하는 데 도움이되는 방식 만 변경됩니다. 함수형 프로그래밍에서 함수-데이터 결합을 원할 때는 컴파일러가 아니라 신사의 동의하에 시행됩니다. OOP에서 모델 뷰 분리는 컴파일러가 아니라 신사 동의에 의해 시행됩니다.


답변

이미이 통찰력이 필요하다는 것을 모르는 경우 : 객체 지향 및 클로저 의 개념은 동일한 동전의 양면입니다. 즉, 폐쇄는 무엇입니까? 주변 범위에서 변수 또는 데이터를 가져 와서 함수 내에서 바인딩하거나 OO 관점에서 예를 들어 생성자에 무언가를 전달하여 나중에 사용할 수 있도록 동일한 일을 효과적으로 수행 할 때 해당 인스턴스의 멤버 함수에있는 데이터 조각 그러나 주변 범위에서 물건을 가져가는 것은 좋은 일이 아닙니다. 주변 범위가 클수록이 작업을 수행하는 것이 더 나쁩니다 (실용적으로 작업을 수행하려면 일부 악이 필요합니다). 전역 변수의 사용은 이것을 프로그램의 함수가 프로그램 범위에서 변수를 사용하는 극단적으로 가져옵니다. 있다전역 변수가 악한 이유에 대한 다른 설명 .

OO 기술을 따르는 경우 기본적으로 프로그램의 모든 모듈에 최소한의 악의가 있음을 이미 동의합니다. 프로그래밍에 대한 기능적 접근 방식을 취한다면 프로그램에 모듈에 클로저 악이 포함되지 않지만 이상이 있지만 OO보다 훨씬 적은 이상적인 것을 목표로 삼고 있습니다.

그것은 OO의 단점입니다. 클로저를 표준 ( 프로그래밍 된 깨진 창 이론) 로 만들어서 이런 종류의 악한 데이터를 결합하여 기능을 수행하도록 장려합니다 .

유일한 장점은, 처음에 많은 클로저를 사용할 것이라는 것을 알고 있다면 최소한 OO는 일반적인 프로그래머가 이해할 수 있도록 접근 방식을 구성하는 데 도움이되는 아이디어 프레임 워크를 제공한다는 것입니다. 특히 닫히는 변수는 함수 클로저에서 암시 적으로 취하는 것이 아니라 생성자에서 명시 적입니다. 클로저를 많이 사용하는 기능적 프로그램은 종종 동등하지 않은 OO 프로그램보다 더 복잡합니다.


답변

타입 커플 링 에 관한 것입니다 .

해당 객체에서 작동하도록 객체에 내장 된 기능은 다른 유형의 객체에서 사용할 수 없습니다.

Haskell에서는 타입 클래스 에 대해 작동하는 함수를 작성합니다. 따라서 함수가 작동하는 주어진 클래스 의 유형이라면 주어진 함수가 작동 할 수있는 다양한 유형의 객체가 있습니다 .

독립형 함수를 사용하면 유형 A 내부에서 작동하도록 함수를 작성하는 데 집중할 때 얻을 수없는 분리가 가능하므로 유형 A 인스턴스가없는 경우에는 함수가 그렇지 않으면 유형 B 인스턴스 또는 유형 C 인스턴스에서 사용하기에 충분히 일반적입니다.


답변

Java 및 이와 유사한 OOP의 구현에서는 다른 모듈에서 인스턴스 메소드 (자유 함수 또는 확장 메소드와 달리)를 추가 할 수 없습니다.

인스턴스 메소드로만 구현할 수있는 인터페이스를 고려할 때 이는 더 많은 제한 사항이됩니다. 다른 모듈에서 인터페이스와 클래스를 정의한 다음 세 번째 모듈의 코드를 사용하여 서로 바인딩 할 수 없습니다. Haskell의 유형 클래스와 같은보다 유연한 접근 방식이 가능합니다.


답변

객체 지향은 기본적으로 절차 데이터 추상화 (또는 직교 문제인 부작용을 제거하는 경우 기능적 데이터 추상화)에 관한 것입니다. 어떤 의미에서, Lambda Calculus는 함수형 데이터 추상화 제공하기 때문에 가장 오래되고 가장 순수한 객체 지향 언어입니다 (함수 이외의 구문이 없기 때문에).

단일 객체 의 조작 만 해당 객체의 데이터 표현을 검사 할 수 있습니다. 같은 유형 의 다른 객체조차 그렇게 할 수 없습니다. (이것은 객체 지향 데이터 추상화와 추상 데이터 유형의 주요 차이점입니다. ADT를 사용하면 동일한 유형의 객체가 서로의 데이터 표현을 검사 할 수 있으며 다른 유형 의 객체 표현 만 숨겨집니다.)

이것은 동일한 유형의 여러 객체가 다른 데이터 표현을 가질 수 있음을 의미합니다. 동일한 객체라도 다른 시간에 다른 데이터 표현을 가질 수 있습니다. (예를 들어, 스칼라에서 Maps와 Sets는 요소의 수에 따라 배열과 해시 트리 간을 전환합니다. 매우 작은 수의 경우 배열의 선형 검색이 매우 작은 상수 요인으로 인해 검색 트리의 로그 검색보다 빠르기 때문에 .)

객체 외부에서 데이터 표현을 알 수 없습니다 . 그것은 타이트한 커플 링 의 반대 입니다.


답변

서로 독립적으로 변경할 수 있기를 원하기 때문에 데이터와 기능 사이의 긴밀한 결합은 나쁘고, 긴밀한 결합은이를 알지 못하고 다른 것으로 변경할 수 없기 때문에이를 어렵게 만듭니다.

함수에 다른 데이터를 표시하여 함수를 변경할 필요가 없으며, 기능 변경을 지원하기 위해 작동중인 데이터를 변경할 필요없이 함수를 변경할 수 있습니다.


답변