객체 지향 함정 방지, C에서 마이그레이션, 무엇이 효과가 있었습니까?


12

나는 지금 절차 언어로 꽤 오랫동안 프로그래밍 해 왔으며, 문제에 대한 나의 첫 번째 반응은 존재하는 다른 엔티티 (객체)와 관계를 고려하기보다는 수행 할 작업으로 나누는 것입니다.

나는 OOP에서 대학 과정을 밟았으며 캡슐화, 데이터 추상화, 다형성, 모듈화 및 상속의 기본 사항을 이해합니다.

내가 읽은 /programming/2688910/learning-to-think-in-the-object-oriented-way/programming/1157847/learning-object-oriented-thinking , 그 답변에서 지적 된 일부 책을 살펴볼 것입니다.

중대형 프로젝트 중 일부는 OOP를 효과적으로 사용하면 도움이 될 것이지만 초보자는 시간이 많이 걸리고 일반적인 오류를 피하고 싶습니다.

당신의 경험에 근거하여, 이러한 함정은 무엇이며 그들 주위의 합리적인 방법은 무엇입니까? 왜 그들이 함정인지 설명하고 문제를 해결하는 데 당신의 제안이 얼마나 효과적인지 설명해 주시면 감사하겠습니다.

나는 "공정한 수의 옵저버와 수정 자 방법을 가지고 있고 개인 변수를 사용 하는가? 또는 그것들을 통합 / 축소하는 기술이 있는가?"

메소드를 혼합 해야하는 이유가 있다면 C ++을 순수한 OO 언어로 사용하는 것에 대해 걱정하지 않습니다. (GOTO를 사용해야하는 이유를 생각 나게하지만, 드물지만)

감사합니다!


2
완전한 답을 얻을 가치는 없지만 받아들이는 데 오랜 시간이 걸렸다 (즉, 많은 시간을 읽었지만 팬보이 대화로 취급). 이렇게하면 좋은 수업 인 수업을 최소한으로 유지할 수 있습니다.
stijn

@stijn 기본적으로 수업에 참여할 필요가 없다면 거기에 두지 마십시오. 예를 들어 지금까지 읽은 코드에서 쉽게 무료 함수가 될 수있는 많은 유틸리티 멤버 함수가 있습니다.
Stephen

그래 그거야. '비회원 비 친구 선호'를 검색하면 이에 대한 많은 정보를 찾을 수 있습니다. 결국 그것은 단일 Responsibility는 원칙을 준수 내려 온다
스테인

답변:


10

내가 배운 한 가지는 외부에서 클래스를 디자인하는 것입니다. 구현에 대해 생각하기 전에 인터페이스를 디자인하십시오. 이렇게하면 기본 알고리즘을 작성하고 클래스를 작성하고 필요에 따라 새 공용 멤버 함수를 작성하는 것보다 클래스를 사용하는 사용자에게 클래스가 훨씬 더 직관적입니다.


7
이에 더하여, 우리는 '의도에 따라 프로그램'할 수 있습니다. 다시 말해, 새로운 클래스를 사용할 샘플 코드를 작성하고 어떤 유형의 메소드와 정책이 사용하기 편한지 확인하십시오. 그런 다음 구현 기준으로 해당 정보를 사용하십시오.

2
이론 상으로는 디자인 인터페이스가 뛰어나고 기본적으로 수행됩니다. 그러나 실제로는 그렇게 간단하지 않습니다. 인터페이스 디자인과 구현은 종종 최종 인터페이스가 결정화 될 때까지 연속 반복으로 진행됩니다. 그 당시에는 최종 구현도 가능할 것입니다.
Gene Bushuyev 2016 년

9

첫 번째는 너무 많은 정보를 노출시키는 함정입니다. 기본값은 private아니 어야합니다 public.

그 후 너무 많은 게터 / 세터가 온다. 데이터 멤버가 있다고 가정 해 봅시다. 나는 마십시오 정말 타 클래스에서이 데이터를해야합니까? 좋아, 게터 만들어 나는 마십시오 정말, reaally 개체의 수명 동안이 데이터를 변경해야합니까? 그런 다음 세터를 만드십시오.

대부분의 초보자 프로그래머는 기본적으로 모든 데이터 멤버에 대해 getter / setter를 만듭니다. 이로 인해 인터페이스가 어수선 해지고 종종 디자인 선택이 잘못됩니다.


2
예, 캡슐화를 표면적으로 이해하여 데이터를 비공개로 만든 다음 게터 및 세터로 캡슐화를 수행하는 사람들에게 매우 인기가 있습니다.
Gene Bushuyev

Java는 여전히 get / set 메소드가 필요한 유일한 대중 언어입니다. 다른 모든 언어는 속성을 지원하므로 공용 데이터 멤버와 속성간에 구문상의 차이가 없습니다. Java에서도 클래스의 모든 사용자를 제어하는 ​​경우 공용 데이터 멤버를 갖는 것은 죄가 아닙니다.
케빈 클라인

공개 데이터 멤버는 유지 관리하기가 어렵습니다. 게터 / 세터 (또는 속성)를 사용하면 외부 코드를 변경하지 않고 내부 데이터 표현을 변경하는 동안 인터페이스를 유지할 수 있습니다. 속성이 소비자 관점에서 멤버 변수와 구문 상 동일한 언어에서는이 점이 유지되지 않습니다.
tdammers

지금까지 나는 개인 멤버를 함수의 로컬 변수로 "일종"보고 있다고 생각합니다 ... 다른 세계는 fn이 작동하기 위해 그들에 대해 아무것도 알 필요가 없습니다 ... 인터페이스 만 일관성을 유지하면됩니다. 나는 스팸 게터 / 세터와 함께 가지 않기 때문에 올바른 트랙에있을 수 있습니다. 실제로 내가 작성한 버퍼 클래스를 보면 공개 데이터 멤버가 전혀 없습니다. 감사!
Stephen

2

그 틈을 건너서 나는 다음과 같은 접근법에 정착했다.

0) 나는 중소 규모의 절차 적 앱으로 느리게 시작했으며 업무상 중요한 것은 없습니다.

1) 프로그램을 처음부터 OO 스타일로 작성하는 방법에 대한 간단한 첫 번째 패스 매핑-그 당시 가장 중요하고 주관적 인 것은 모든 기본 클래스를 파악하는 것이 었습니다. 내 목표는 기본 클래스에서 가능한 한 많이 캡슐화하는 것이 었습니다. 기본 클래스에서 가능한 모든 것을위한 순수한 가상 메소드.

2) 다음 단계는 파생을 만드는 것입니다.

3) 마지막 단계는 원래 절차 코드에서 데이터 구조를 obsever / modifier 코드와 분리하는 것입니다. 그런 다음 데이터 숨기기를 사용하고 모든 공통 데이터를 기본 클래스에 맵핑하고 서브 클래스에서 프로그램 전체에서 공통적이지 않은 데이터를 사용했습니다. 그리고 절차 적 관찰자 / 수정 자 코드에 대한 동일한 처리-모든 '모든 곳에서 사용되는'논리가 기본 클래스로 들어갔습니다. 그리고 데이터의 하위 집합에만 작용하는 논리를 보거나 수정하면 파생 클래스로 들어갑니다.

절차 적 코드와 데이터 구조를 잘 알고 있다면 주관적이지만 빠릅니다 . 코드 검토에서 실패는 약간의 데이터 또는 논리가 기본 클래스에 나타나지 않지만 어디서나 사용되는 경우입니다.


2

좋은 스타일을 얻기 위해 OOP를 사용하는 다른 성공적인 프로젝트를 살펴보십시오. 내 자신의 디자인 결정을 할 때 항상 찾는 프로젝트 인 Qt를 보는 것이 좋습니다 .


예! 사람이 무언가의 주인이되기 전에, 그는 자신보다 먼저 일했던 위대한 주인을 본받는 법을 배웁니다. 다른 사람이 구현 한 좋은 코드를 공부하는 것은 배우는 좋은 방법입니다. 단순한 디자인부터 시작하여 이해력이 향상됨에 따라 더 깊이 부스트하는 것이 좋습니다.
Gene Bushuyev 2016 년

1

대화하는 사람에 따라 OOP의 모든 데이터는 개인 또는 보호되어야하며 접근 자와 뮤 테이터를 통해서만 사용할 수 있습니다. 일반적으로 이것이 좋은 습관이라고 생각하지만이 표준과 다른 경우가 있습니다. 예를 들어, 클래스의 일부 (Java의 경우)가 일부 데이터 조각을 논리 단위로 비우는 것이 유일한 목적이라면 필드를 공개 상태로 두는 것이 좋습니다. 불변 캡슐 인 경우 최종 표시를하고 생성자에서 초기화하면됩니다. 이렇게하면 클래스 (이 경우)를 구조체 이상으로 줄입니다 (실제로 C ++을 사용하면 실제로 이것을 구조체로 호출해야합니다. 클래스와 동일하게 작동하지만 기본 가시성은 공개되어 있으며 의도는 더 명확합니다). 이 경우에는 사용하는 것이 훨씬 편안하다는 것을 알게 될 것입니다.

분명히 원하지 않는 한 가지는 뮤 테이터의 일관성을 검사하고 공개 해야하는 필드가 있다는 것입니다.


3
또한 공개 데이터를 보유하는 클래스가있는 경우 클래스를 structs 로 선언해야합니다. 의미 론적 차이는 없지만 의도를 명확하게하고 특히 C 프로그래머에게 더 자연스러운 것처럼 보이게합니다.

1
네, C ++ (질문에 언급 된)에 있다면 여기에 동의하지만 Java에서 대부분의 작업을 수행하지만 불행히도 구조체가 없습니다.

집계 클래스 (흔하지 않은 경우)와 기능이있는 클래스 (일반적인 경우)를 명확하게 구분해야합니다. 후자는 캡슐화를 연습하고 공용 인터페이스를 통해서만 멤버에 액세스해야합니다. 데이터는 공개되지 않아야합니다.
유전자 Bushuyev

1

Kent Beck의 책 Implementation Patterns는 오용이 아닌 객체 지향 메커니즘을 사용하는 방법에 대한 훌륭한 토대입니다.


1

메소드를 혼합 해야하는 이유가 있다면 C ++을 순수한 OO 언어로 사용하는 것에 대해 걱정하지 않습니다. (GOTO를 사용해야하는 이유를 생각 나게하지만, 드물지만)

나는이 비트를 볼 때까지 대화를 제공 할 것이 많지 않다고 생각했습니다. 감정에 동의하지 않아야합니다. OOP는 C ++에서 사용할 수 있고 사용해야하는 패러다임 중 하나 일뿐입니다. 솔직히 말해서, 그것은 가장 강력한 기능 중 하나가 아닙니다.

OO 관점에서 C ++은 실제로 약간 부족하다고 생각합니다. 예를 들어 비가 상 기능을 갖는 아이디어는 이와 관련하여 그것에 대한 진드기입니다. 나는 동의하지 않는 사람들과 논쟁을 벌였지 만 비가 상 구성원은 내가 생각하는 한 패러다임에 맞지 않습니다. 다형성은 OO의 핵심 구성 요소이며 비가 상 함수가있는 클래스는 OO 의미에서 다형성이 아닙니다. OO 언어로서 C ++은 Java 또는 Objective-C와 같은 언어와 비교할 때 실제로 다소 약하다고 생각합니다.

반면에 일반 프로그래밍 인 C ++에는 꽤 좋은 기능이 있습니다. 나는 이것에 대해 더 나은 언어가 있다고 들었지만, 객체와 일반 함수의 조합은 매우 강력하고 표현적인 것입니다. 또한 프로그래밍 시간과 처리 시간 모두에서 빠를 수 있습니다. 실제로이 분야에서는 C ++이 빛을 발한다고 생각하지만 더 좋을 수도 있습니다 (예 : 개념에 대한 언어 지원). 누군가가 OO 패러다임을 고수하고 부도덕 한 수준에서 goto 진술의 순서대로 다른 사람들을 대해야한다고 생각하는 사람은이 패러다임을 보지 않으면 실제로 빠져 있습니다.

템플릿의 메타 프로그래밍 기능도 매우 인상적입니다. 예를 들어 Boost.Units 라이브러리를 확인하십시오. 이 라이브러리는 차원 수량에 대한 유형 지원을 제공합니다. 현재 근무중인 엔지니어링 회사에서이 라이브러리를 광범위하게 사용했습니다. 그것은 가능한 프로그래머의 한 측면이나 심지어 사양 오류에 대한 훨씬 더 즉각적인 피드백을 제공합니다. '='연산자의 양쪽이 명시 적 캐스팅없이 차원 적으로 동일하지 않은 수식을 사용하는 프로그램은 컴파일 할 수 없습니다. 나는 개인적으로 이것이 가능한 다른 언어에 대한 경험이 없으며 C ++의 힘과 속도를 가진 언어에는 전혀 경험이 없습니다.

메타 프로그래밍은 순전히 기능적인 패러다임입니다.

실제로, 나는 당신이 이미 불행한 오해로 C ++에 들어서고 있다고 생각합니다. OO 이외의 다른 패러다임을 피하지 말고 활용해야합니다. 작업중인 문제의 측면에서 자연스러운 패러다임을 사용하십시오. 본질적으로 물체가 발생하기 쉬운 문제가 아닌 물체에 물체를 강요하지 마십시오. 내가 아는 한, OO는 C ++에 대한 이야기의 절반도 아닙니다.


virtual 키워드가 C ++에서 가상 클래스 기능을 제공하지 않습니까? goto 의견에 이르기까지, 내가 운전하고 있던 것은 추론을 이해하는 한 경험적 규칙을 어기는 것에 대해 걱정하지 않는다는 것입니다. 그러나 나는 필요 이상으로 OO에 찬성하여 명령 적 / 절차를 줄이려고 노력하고있다. 감사.
Stephen

가상 방법은 다형성의 전제 조건이 아니며 일반적인 방법입니다. 실제로, 다른 모든 것이 동일하면 메서드를 가상으로 만들면 실제로 캡슐화가 약해집니다. 클래스의 api 크기가 커지고 liskov 등을 따르기가 더 어려워지기 때문입니다. 이음새가 필요한 경우에만 가상의 무언가를 만드십시오. 상속을 통해 새로운 행동을 주입 할 수있는 곳입니다 (상속성은 OOP에서 조심해야 할 것이지만). 가상을 위해 가상은 "더 많은 OOP"클래스를 만들지 않습니다
sara

1

이 질문에 대한 답변을 받고 싶었지만 확인 표시를 할 하나의 답변을 결정할 수 없었습니다. 따라서 나는 원래의 저자를 찬성하고 이것을 요약 답변으로 만들었습니다. 몇 분이 소요 된 모든 사람들 덕분에, 당신이 제공 한 통찰력이 나에게 좋은 방향과 약간의 확신을 주 었음을 알게되었습니다.

@nightcracker

첫 번째는 너무 많은 정보를 노출시키는 함정입니다. 기본값은 공개가 아닌 개인용이어야합니다. 그 후 너무 많은 게터 / 세터가 온다.

나는 과거에이 문제가 실제로 행동하고 있음을 느꼈다. 귀하의 의견에 따르면 기본 변수와 구현을 숨기면 변수에 의존하는 것을 파괴하지 않고 구현을 자유롭게 변경할 수 있습니다.

도미니크 구르 토

구현에 대해 생각하기 전에 인터페이스를 디자인하십시오. Gene Bushuyev 인터페이스 설계 및 구현은 종종 최종 인터페이스가 결정화 될 때까지 연속 반복으로 진행됩니다.

나는 도미니크의 논평이 열망하는 데 이상적이라고 생각했지만, 진의 의견은 실제로 상황의 현실에 영향을 미친다고 생각합니다. 지금까지 나는 이것을 실제로 보았습니다 ... 그리고 드문 일이 아니라는 것이 조금 나아졌습니다. 프로그래머로서 성숙해지면서 더 완벽한 디자인을 기대하지만 지금 당장은 여전히 ​​문제가 생겨 코드를 작성합니다.

wantTheBest

나는 중소 규모의 절차 적 앱으로 느리게 시작했으며 업무상 중요한 것은 없습니다. 원래 절차 코드에서 데이터 구조를 obsever / modifier 코드와 분리하십시오.

이것은 일의 일을 계속 유지한다는 개념을 좋아했지만 클래스를 사용하여 중요하지 않은 것들을 리팩토링하는 것이 좋습니다.

jpm

분명히 원하지 않는 한 가지는 뮤 테이터에서 일관성을 검사해야하는 필드를 가지고 공개하는 것입니다.

나는 이것이 데이터를 캡슐화하는 강점 중 하나라는 것을 알고 있습니다 ... 일관성을 유지하고 그 문제 조건 / 범위 / 등을 위해.

크레이지 에디

누군가가 OO 패러다임을 고수하고 부도덕 한 수준으로 goto 진술의 순서대로 다른 사람들을 대해야한다고 생각하는 사람은이 패러다임을 보지 않으면 실제로 빠져 있습니다. 템플릿의 메타 프로그래밍 기능도 매우 인상적입니다.

크레이지 에디의 답변에서 원래 많은 부분을 놓쳤습니다. 메타 프로그래밍과 같은 언급 된 주제 중 일부를 읽지 않았기 때문입니다. CE의 게시물에서 훌륭한 메시지는 C ++이 각각의 기능과 스타일을 혼합하여 최상의 잠재력을 발휘해야한다는 것입니다.

다시 한번 답변 해 주신 모든 분들께 감사드립니다!


0

가장 큰 함정은 OOP가은 총알 또는 "하나의 완벽한 패러다임"이라는 믿음입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.