private, protected는 필요한건가요?

ed.netdiver의 이미지

python을 공부하다보니, class가 여느 (어설프게 알고있던)class개념과
사뭇 달랐습니다.
member를 동적으로 할당할수 있달지,
모든 member가 public이랄지요.
이에 대한 설명을 보면, 물론 그걸 감추는 방법도 있긴 하지만,
원천적으로 namespace에 대한 접근만 할수 있다면, 접근이
가능하게 되어 있으며, private, protected는 중요하지 않다고 하더군요.
cpp랄지 하는 책들 보면, 앞장에 나오는것중에 하나가 private, protected인지라,
뭐랄까 신선했다고나 할까요.

우선, 가드를 긋자면, 저는 cpp로 그렇게 큰규모의 프로그래밍을 해본적이
없습니다.(template조차 써본적 없으니 말 다했죠?^^;)
디자인 패턴, 리팩토링정도까지 '읽어본' 수준이라고 보시면 됩니다.
그러니, 초심자를 가르친다 셈 치시고,
과연 private, protected가 진짜 필요한건지, 그리고 그렇다면
어떤 경우에 어떻게 사용한달지, 개념적으로(?^^;) 이야기를
해봤으면 해서 이 글을 포스트해봅니다.
(실은 어차피 memory상에서 plain하게 펼쳐놓고 보면,
접근성이란걸 회피할수 없지 않냐는 황당한 생각까지 할정도로
개념없는 수준이예염.ㅠ.ㅠ;)

qna에 올리기는 좀 두리뭉실한 감이 있어서 이곳에 올립니당.
(이글도 flame성인가?ㅡ.ㅡ; 앗싸~)

그럼 좋은 하루하루 되세요.

File attachments: 
jj의 이미지

(자바의 예를 들면)

private은 저도 쓰기싫더군요. 개인적으로 private이냐 아니냐 보다, public 이냐 아니냐가 더 중요하다고 생각합니다.

"필드는 무조건 private!" 이라고 얘기하는 사람들 대부분은 "getter, setter는 무조건 public!" 이더군요. 어이없는 일이죠. ^^

package레벨의 modifier가 중요하다고 생각합니다.

--
Life is short. damn short...

doldori의 이미지

저는 접근 권한을 구분하는 것이 매우 도움이 된다고 봅니다. 보통 private/protected
멤버는 구현에 관련된 것들이죠. 잘 설계된 클래스는 public 인터페이스만을 통하여
클라이언트가 원하는 기능을 제공하고 디테일한 구현은 감춤으로써 코드를 유연하게
만들 수 있습니다. 예를 들어 C++의 std::string과 비슷한 역할을 하는 String이라는
클래스를 만든다고 합시다. 보통 입문서에서 나오는 식으로 내부에 char*가 있고
스트링의 길이에 따라 new를 하며 복사를 할 때마다 따로 메모리를 할당하여
복사하는 식으로 구현을 했다고 가정합시다. 그런데 실제로 사용하다 보니 복사가
매우 빈번하고 따로따로 메모리를 할당하는 것이 비효율적이어서 reference
counting을 하는 식으로 구현 방법을 바꾼다고 합시다. 만약 구현에 관련된 멤버까지
public으로 했다면 클래스 구현의 변경은 거의 불가능할 것입니다. 구현이 바뀐다면
클래스의 데이터 멤버가 바뀌게 될 것이고 그 데이터 멤버를 사용한 클라이언트의
코드는 수정을 해야 하기 때문이지요. 공개용 라이브러리나 상용 코드의 경우에는
심각한 문제입니다. public 인터페이스만 그대로 두고 구현에 관련한 것들은
private/protected로 만듦으로써 필요에 따라 변경이 가능한 것이 추상화와
캡슐화의 장점 아니겠습니까.
또다른 예로 gcc의 std::vector는 _M_start라는 protected 멤버가 있습니다.
반면에 .NET에서는 _Myfirst라는 멤버가 있지요. 만약 이들이 public이어서
vector의 인터페이스를 통하지 않고 바로 접근한다면 이식성이 없는 코드가 되고
vector 클래스의 invariant도 보장할 수 없을 것입니다.
이것들이 접근 권한에 구분을 두는 것이 좋다고 보는 이유입니다.

jj님께서 getter/setter를 말씀하셨는데 이것은 충분히 추상화되지 않은 클래스에서
흔히 볼 수 있는 증상 같습니다. 디테일한 구현을 인터페이스로 위장한 것이죠.
저 같으면 클래스 설계를 다시 검토해 보겠습니다.

ddoman의 이미지

설계한 클래스를 혼자 사용하거나,
1회성으로 사용할 경우는 필요가 없습니다( 바람직하다고 생각지는 않지만 )

저는 private, protected 역시 const 와 쓰는 마찬가지인 이유로 쓴다고 생각합니다.

그런것들은 코드상에서 잠재적인 버그를 만들 수 있는 확률을 확실하게 줄여주며, 컴파일시에 잡을 수 있게 도와줍니다.

코드를 짤 때는
"내가 만든 코드는 항상 누군가 보고 이용( 재활용 ) 될 수 있다 "
라는 생각을 갖고 해야합니다.

자신이 짠 코드를 이용하는 사람들이 항상 자신이 원하는대로
이용할 거라고 생각하지 마십시오.
자세한 메뉴얼도 도움이 되겠지만 해당 언어에서 제공하는
키워드를 이용하여 코드의 이용을 제한하는것이 효과적입니다.

그런면에서 private, protected, const 등등은 인터페이스, 자원 등을 단일화, 강제화 시킬 수 있으며 이러한 코딩 습관은 발생 가능 한 수 많은 버그의 경우의 수를 줄여 줍니다.

nainu의 이미지

마틴 파울러의 리팩토링을 보면 멤버 변수를 private으로 바꾼 후에 컴파일로 그 변수를 외부에서 참조하는지 아닌지를 검사하지요.. 저는 php와 python을 주로 사용하는 코더인데요, 리팩토링을 할 때나, 꼭 리팩토링이 아니라고 해도 변수를 숨기거나 다른 곳으로 옮기고자 할때 private 키워드가 있으면 작업이 편할 거라고 자주 생각했었습니다.

그래서 요새는 변수 이름 앞에 밑줄을 붙이고 문법 검사기를 사용하는 편입니다. :)

ed.netdiver의 이미지

nainu wrote:
마틴 파울러의 리팩토링을 보면 멤버 변수를 private으로 바꾼 후에 컴파일로 그 변수를 외부에서 참조하는지 아닌지를 검사하지요.. 저는 php와 python을 주로 사용하는 코더인데요, 리팩토링을 할 때나, 꼭 리팩토링이 아니라고 해도 변수를 숨기거나 다른 곳으로 옮기고자 할때 private 키워드가 있으면 작업이 편할 거라고 자주 생각했었습니다.

그래서 요새는 변수 이름 앞에 밑줄을 붙이고 문법 검사기를 사용하는 편입니다. :)


python에서 밑줄은 하나붙이시나요, 두개 붙이시나요?
찾아보고 말씀드려야겠지만, 두개 붙여야 private속성을 가진다고
했던것 같아서요...

--------------------------------------------------------------------------------
\(´∇`)ノ \(´∇`)ノ \(´∇`)ノ \(´∇`)ノ
def ed():neTdiVeR in range(thEeArTh)

익명 사용자의 이미지

답답하십니다..

getter/setter는 JavaBeans Spec. 에 명시된 규약입니다.
윗분은 추상화와 인터페이스.. 로 잘 설명하다가 삼천포로 빠졌습니다. 그려..

추상화가 잘 된 자바 클래스에서 getter/setter를 씁니다.
클래스 설계를 다시 하기전에 코딩을 더 해보시길 바랍니다.

인터페이스 자체가 public method의 signature입니다.
디테일한 구현을 인터페이스로 위장? 한게 아니라 디테일한 구현을 숨기고(encapsulation) 그 구현을 노출(Interface) 하는 것이기때문에 위장이 아닙니다.
Concrete class도 Abstract Class도 Interface 도 모두 외부 Interface입니다.

자바 스펙에 getter/setter convention을 정의했기때문에 이 Method를 사용하는 것입니다.

Abstract Method와 Interface의 차이를 이해하지 못하면 절대 좋은 설계가 나오질 않습니다.
왜 이것 두개를 만들어 두었을까요?

객체지향의 어떤 책을 보더라도 제일 처음 나오는것이 클래스의 접근자인데 이걸 한마디로 딱 끊어서 '어어없다'고 하는 그 무식이 참으로 경악스럽습니다.

..

정리하자면 모든 클래스의 멤버는 private 혹은 protected로 접근제한을 주는것이 바람직합니다. 이것이 이해가 안되면 객체지향은 물건너 갔습니다.

규약을 지키지않아도 시스템은 잘 돌아갑니다만 왜 대가들이 그런 말을 했을까? 최소한 1분정도는 고민해 보시길 바랍니다.

너무 길어서 글을 줄입니다만.. 힘이 쭉 빠지는 글이었습니다..

이 정도밖에 안됩니까? 여기?

죠커의 이미지

ddoman wrote:
설계한 클래스를 혼자 사용하거나,
1회성으로 사용할 경우는 필요가 없습니다( 바람직하다고 생각지는 않지만 )

저는 private, protected 역시 const 와 쓰는 마찬가지인 이유로 쓴다고 생각합니다.

제대로 된 코드라면 const를 쓰다고 해서 재 사용성이 더 높아 지거나 줄어들지는 않는 것 처럼 private와 protected도 마찬가지라고 생각합니다. 더 견고한 코드를 위한 장치라는게 더 옳지 않을까 합니다. :-)

Anonymous wrote:
답답하십니다..

getter/setter는 JavaBeans Spec. 에 명시된 규약입니다.
윗분은 추상화와 인터페이스.. 로 잘 설명하다가 삼천포로 빠졌습니다. 그려..

추상화가 잘 된 자바 클래스에서 getter/setter를 씁니다.
클래스 설계를 다시 하기전에 코딩을 더 해보시길 바랍니다.

인터페이스 자체가 public method의 signature입니다.
디테일한 구현을 인터페이스로 위장? 한게 아니라 디테일한 구현을 숨기고(encapsulation) 그 구현을 노출(Interface) 하는 것이기때문에 위장이 아닙니다.
Concrete class도 Abstract Class도 Interface 도 모두 외부 Interface입니다.

자바 스펙에 getter/setter convention을 정의했기때문에 이 Method를 사용하는 것입니다.

JSP를 할때 간단히 빈즈를 써본 적이 있습니다. 그것과 비슷한 이유로 접근자를 사용한다면 환경의 제약으로 인한 어쩔 수 없는 사용이라고 봅니다.

대부분의 접근자를 제공하는 객체는 접근자가 가리키는 데이터를 public으로 공개하는 것과 별반 다르지 않는 구조를 가지고 있습니다. 접근자로 추상화나 인터페이스를 보강해준 다는 것은 단신의 키로 덩크를 하는 것 만큼 힘이 들 것입니다. 더구나 접근자로 도배된 객체는 호박에 줄 그어 놓은 것 이상의 가치는 가지기 힘들다고 봅니다. 덧붙여 C#에서 접근자를 체계화 하기 위한 프로퍼티 특성도 과잉 기능이며 필요없는 특성이라고 생각합니다.

PS: 위대한 대가들도 public만으로 실무에 응한 적도 있습니다. OTL

FlOw의 이미지

클래스 멤버에서 변수는 private,protected로 메쏘드는 public으로
private은 외부에서 직접접근 못하므로 접근가능한 public메소드로 접근하게 만들어 써서, 클래스을 쓸때 일일이 변수이름을 확인할필요 없이 메소드로 접근하면 편하고 변수가 노출되지 않으니 잘못된 코딩을 피할수 있다고 알고 있는데 맞는건지 :oops:

-------------------- 절취선 --
행복하세요:)

byung82의 이미지

변수 접근은 public 보다는 getter setter로 접근하시는게 좋습니다.

간단한 예로

class test
{
public:
char *temp;
}

test test;

std::count << test.temp;

이렇게 하면 exception이 호출됩니다.

그러니 getter, setter로 하시면 데이터 보호를 하실수 있습니다.

class test
{
private:
char* temp;
public:
char* get_temp( void ) { return temp == NULL ? "" : temp; }
};

std::count << test.get_temp();

이렇게 하면 데이터를 처리 하면서 문제점 하나를 해결해 줄수 있습니다.

실제로 setter로 하실때도 미리 문제점 될만한것을 체크 하고 피하기 또는 exception을 내줄수도 있습니다 ^^;

변수의 접근을 될수 있으면 데이터 보호 차원에서 getter, setter를 활용해주시는게 좋습니다.

맘아픈건 c++ 에서는 property가 없다는거죠 ^^:

그럼

snaiper의 이미지

doldori wrote:

jj님께서 getter/setter를 말씀하셨는데 이것은 충분히 추상화되지 않은 클래스에서
흔히 볼 수 있는 증상 같습니다. 디테일한 구현을 인터페이스로 위장한 것이죠. 저 같으면 클래스 설계를 다시 검토해 보겠습니다.

저는 이 말에 동의하는 쪽에 속합니다. 특별한 경우가 아니고서는 오히려 캡슐화 자체를 약화시키는 것이 아닌가 생각합니다.

손님 wrote:

답답하십니다..

getter/setter는 JavaBeans Spec. 에 명시된 규약입니다.
윗분은 추상화와 인터페이스.. 로 잘 설명하다가 삼천포로 빠졌습니다. 그려..

추상화가 잘 된 자바 클래스에서 getter/setter를 씁니다.
클래스 설계를 다시 하기전에 코딩을 더 해보시길 바랍니다.

인터페이스 자체가 public method의 signature입니다.
디테일한 구현을 인터페이스로 위장? 한게 아니라 디테일한 구현을 숨기고(encapsulation) 그 구현을 노출(Interface) 하는 것이기때문에 위장이 아닙니다.
Concrete class도 Abstract Class도 Interface 도 모두 외부 Interface입니다.

자바 스펙에 getter/setter convention을 정의했기때문에 이 Method를 사용하는 것입니다.

이렇게 말하신데에 대해서는 글쎄요...라고 말하고 싶네요. 위에 언급한대로 빈즈가 특수한 경우가 아닐까 합니다. getter/setter에 대한 주제는 이미 언급된 바가 있습니다.관련 주제에 대한 아티클을 하나 가지고 있어 첨부해봅니다.첨부된 아티클을 보시면 getter/setter 에 대한 문제점을 알 수 있을겁니다. 물론 언급하시는 그 Java 쪽에서 나온 문서고요.

ps. 출처는 pdf 파일 내부에 있으므로 굳이 밝히지는 않겠습니다.
ps2. 다시 보니 빈즈 얘기도 나왔었군요 ^^:

댓글 첨부 파일: 
첨부파일 크기
PDF icon 0바이트
nainu의 이미지

qed wrote:
nainu wrote:
마틴 파울러의 리팩토링을 보면 멤버 변수를 private으로 바꾼 후에 컴파일로 그 변수를 외부에서 참조하는지 아닌지를 검사하지요.. 저는 php와 python을 주로 사용하는 코더인데요, 리팩토링을 할 때나, 꼭 리팩토링이 아니라고 해도 변수를 숨기거나 다른 곳으로 옮기고자 할때 private 키워드가 있으면 작업이 편할 거라고 자주 생각했었습니다.

그래서 요새는 변수 이름 앞에 밑줄을 붙이고 문법 검사기를 사용하는 편입니다. :)


python에서 밑줄은 하나붙이시나요, 두개 붙이시나요?
찾아보고 말씀드려야겠지만, 두개 붙여야 private속성을 가진다고
했던것 같아서요...

하나입니다. 명시적으로 private 용도로 사용하는것을 표시하려고요. 나중에 그 변수를 가지고 TDD에 사용하기도 합니다.. :)

htna의 이미지

제가보기에, public, private는 반듯이 있어야 합니다.
하지만 경우에 따라서 protected보다는 package(C++에는 이러한 기능을 하는게 없죠)가 더 유용하지 않나 생각 듭니다.
public, private, package 정도만 있으면 충분하지 않을까..
protected는 경우에따라 (가급적) 없어졌으면 하는 바램이 있습니다.
회사의 프로그램이 덩치가 커지다보니 (좀 심각하게 커요..)
자잘한 protected 때문에 골치겪는 경우가 많습니다.
다른분들은 어떻게 생각하시는지...

PS:
protected 가 프로젝트와 class간의 상속관계가 좀 깊어지고, 복잡해질때 문제가 커지게 되죠..
그 protected 변수를 어느 클래스에서 상속받았고, 또 어느 상속된 클래스에서 언제 사용되었는지가 추적이 매우 용이하지 않죠..
차라리 public 과 private 만 있다면, 맘 편하게 값을 추적하면서 디버깅 할 수 있는데 말이죠...
머, 프로그램을 완벽하게 잘 짜실 수 있는 분들은... 상관 없겠지만,
여러사람이 공동작업 하는 경우에야..
내가 만지다가, 다른사람이 만질수도 있고, 내가 다른사람이 만지던걸 디버깅 할 수도 있고 하니깐요...
PS2:
에궁 protected대신 몽땅 private만 썼군요.
모두 수정했습니다.
오해 없으시길.. ^^;;

WOW Wow!!!
Computer Science is no more about computers than astronomy is about telescopes.
-- E. W. Dijkstra

죠커의 이미지

byung82 wrote:
변수 접근은 public 보다는 getter setter로 접근하시는게 좋습니다.

아래 두 코드는 Alexander Stepanov의 것 입니다.

pair<int, int> tmp = my_vector.get(i);
tmp.second = 5;
my_vector.put(i, tmp);

이 코드 보다

i->second = 5;

이 코드가 더 나은 것 같지 않습니까?

접근자가 필요없는 수준의 추상화가 힘들면 그냥 내버려 범용성을 올리는 편이 더 유익하다고 생각합니다.

htna wrote:
제가보기에, public, private는 반듯이 있어야 합니다.

private가 없는 훌륭한 객체지향 언어도 있습니다. :-)

htna의 이미지

CN wrote:
private가 없는 훌륭한 객체지향 언어도 있습니다. :-)

물론 private없는 훌륭한 객체지향 언어도 있습니다.
저도 그러한 언어 (ML이 그랬죠? HASKEL은 제가 배울때 없어서리.. 어떤지 모르겠습니다만) 를 배우면서 감탄을 금치 못했구요...
하지만 객체지향과 encapsulation과는 다른말인듯 합니다만...
객체(행동 + 상태)지향과 encapsulation(공개,은닉)은 근본적으로 좀 다른놈이 아닌가 생각합니다.
(물론 객체지향에 encapsulation을 포함하고 있지만, 좀 다른 시각에서 바라봤습니다... ^^)

CN wrote:
더구나 접근자로 도배된 객체는 호박에 줄 그어 놓은 것 이상의 가치는 가지기 힘들다고 봅니다. 덧붙여 C#에서 접근자를 체계화 하기 위한 프로퍼티 특성도 과잉 기능이며 필요없는 특성이라고 생각합니다.

전 다르게 생각합니다. 실제로 class디자인은 간단하게 시작하는것이 때에따라서는 매우 좋다고 생각합니다. 이런경우 멤버변수를 public으로 놓고 시작하는것이 초기에 매우 편합니다. 하지만, 이경우 class가 진화(진화란 표현을 저는 자주 사용합니다. 실제로 class가 변화하면서 더 나아지는게 일반적이니깐요)하면서 public member variable 이 복잡한 상호협력을 위해서 위해서 변수의 type이 변할 수도 있고, 혹은 디버깅을 위해서 변수를 접근하여 사용하는데 특정 이벤트등이 추가될 수도 있습니다. 이경우 이 class를 사용하는 소스를 모두 찾아서 고쳐야 합니다. 그게 쉬운작업만은 아니라는것을 이미 어느정도 아시리라 믿습니다. 하지만, 이미 접근자로 객체의 멤버에 접근이 제한되어 있을 경우에는, 이 문제가 아주 간단하게 해결됩니다.
실제 실무 어플리케이션을 만드는 데 있어서, 이러한 경우를 많이 겪고 있습니다.
이런경우, 이런일이 필요할때마다 클래스를 다시 만들라고는 하지 않으시겠죠?
솔직히 C++에서 C#에서처럼 접근자를 만들어줬으면 하는때가 종종 있습니다만...

PS:
제가 학부 졸업한지 몇년정도 되서, 많이 잊어먹어서 좀 틀릴지도 모릅니다.
틀린부분 있다면 가차없이 지적해주시길.. ^^

PS2:
이거 한글 깨지는거 좀 어케 할 수 없나요 ?
너무 불편합니다.

WOW Wow!!!
Computer Science is no more about computers than astronomy is about telescopes.
-- E. W. Dijkstra

khris의 이미지

아직 초보이긴 하지만...

멤버변수를 public으로 방치해놓는것보다는 setter나 getter가 있는것이 낫다고 생각합니다.

잘못된 값이 들어왔을 경우를 예방해 줄수도 있고...

뭐 그래서 개인적으로는 VB의 property 속성을 좋아합니다.

멤버변수쓰듯 하면서 사실상 getter와 setter를 셋팅해놓으니까요.

myObj.SetValue(13)

보다는

myObj.Value = 13

후자쪽이 좀 더 괜찮지 않은가요? :)

───────────────────────
yaourt -S gothick elegant
khris'log

jj의 이미지

Anonymous wrote:

객체지향의 어떤 책을 보더라도 제일 처음 나오는것이 클래스의 접근자인데 이걸 한마디로 딱 끊어서 '어어없다'고 하는 그 무식이 참으로 경악스럽습니다.

익명씨가 제글 보시고 그런것 같군요. 쓰지 말자고 한건 아니구요. getter, setter도 좋지만(비록 전 쓰기 귀찮지만-_-), public, private도 좋지만, 패키지 레벨도 알고 쓰라는 얘기죠. 무식이 경악 스러웠다니..... ㅋ 어떻게 반응해야 할지... 허허...

--
Life is short. damn short...

ed.netdiver의 이미지

좋은 답변들 감사합니다.
덕분에 많은 공부가 되었습니다.^^;

앞의 손님분들중 한분께서 말씀하셨듯이, 접근자도 책 앞머리에
나오는 개념이긴 하죠.
그런데 제가 접근자를 사용하는데 있어서 조금 갑갑했달지 했던건
뭐랄까 코드가 직관적이지 못하지 않냐는 점이었습니다.
그부분에 있어서 python은 보다 직관적인 형태의 코딩을 추천하고
있는것 같습니다.

private, protected의 경우, 상속시에 superclass의 정보를
은닉하고자 하고, 또한 정보의 비정상적인 접근을 막겠다는 것이
본 취지인건 알겠는데, 앞서 리팩토링에서 언급되었듯,
그건 '코드레벨'에서의 debugging용으로 사용되는 수준(runlevel접근도 당연히)
다시말해, data scope의 견고함을 위한 것으로만 받아들일 것이냐,
그 외적인 다른 용도가 있는 것이냐에서 아리까리합니다.

접근성에 제한을 두는게 설계를 강건하게 하는것으로 보이는것에는
동의합니다. 다만, 명백히 설계미스이긴 하지만,
s/w개발시 명세에 분명히 protected로 분류해놓은 것을 차후
유지보수하다가 private으로 끌어내줘야 한달지 하는 경험,
혹시 없으십니까? 저는 매우 자주 그런 경험을 하고 있거든요.^^;

그럼 좋은 하루하루 되세요~~~

덧. jj님의 실력이야 익히 알고들 계신데, 비록 손님분께서 의견개진중에
좀 무례한 발언을 했다고 해도, 너그러이 받아들여주세요^^;
아님, 걍 '메롱~' 해주시던지요...ㅋㅋ
(제 반응은, 아이 민망^^;이 되겠지만요^^;)

--------------------------------------------------------------------------------
\(´∇`)ノ \(´∇`)ノ \(´∇`)ノ \(´∇`)ノ
def ed():neTdiVeR in range(thEeArTh)

meteors의 이미지

qed wrote:

다만, 명백히 설계미스이긴 하지만,
s/w개발시 명세에 분명히 protected로 분류해놓은 것을 차후
유지보수하다가 private으로 끌어내줘야 한달지 하는 경험,
혹시 없으십니까? 저는 매우 자주 그런 경험을 하고 있거든요.^^;

그런일이 흔하게 일어나니까 refactoring이 있겠죠. :D
문제에 대해 잘 모른다던지, 해결할 문제가 바뀌었다던지, 실수했다던지 하는 경우는 항상 벌어지니까요.
죠커의 이미지

한가지 의문점이 드는 군요.

STL의 저자 Alexander Stepanov는 setter / getter를 싫어하는 사람입니다. 접근자를 선호하시는 분들은 C++ STL의 구조에 대해서 어떻게 생각하십니까?

죠커의 이미지

htna wrote:
CN wrote:
private가 없는 훌륭한 객체지향 언어도 있습니다. :-)

물론 private없는 훌륭한 객체지향 언어도 있습니다.
저도 그러한 언어 (ML이 그랬죠? HASKEL은 제가 배울때 없어서리.. 어떤지 모르겠습니다만) 를 배우면서 감탄을 금치 못했구요...
하지만 객체지향과 encapsulation과는 다른말인듯 합니다만...
객체(행동 + 상태)지향과 encapsulation(공개,은닉)은 근본적으로 좀 다른놈이 아닌가 생각합니다.
(물론 객체지향에 encapsulation을 포함하고 있지만, 좀 다른 시각에서 바라봤습니다... ^^)

객체지향 하면 흔히 말하는 Smalltalk가 public으로만 이루어졌었던 걸로 기억합니다. :-)

객체지향적인 프로그램 설계와 견고한 프로그래밍을 위한 도구는 조금 다르다는 것에 동의합니다.

htna wrote:
CN wrote:
더구나 접근자로 도배된 객체는 호박에 줄 그어 놓은 것 이상의 가치는 가지기 힘들다고 봅니다. 덧붙여 C#에서 접근자를 체계화 하기 위한 프로퍼티 특성도 과잉 기능이며 필요없는 특성이라고 생각합니다.

전 다르게 생각합니다. 실제로 class디자인은 간단하게 시작하는것이 때에따라서는 매우 좋다고 생각합니다. 이런경우 멤버변수를 public으로 놓고 시작하는것이 초기에 매우 편합니다. 하지만, 이경우 class가 진화(진화란 표현을 저는 자주 사용합니다. 실제로 class가 변화하면서 더 나아지는게 일반적이니깐요)하면서 public member variable 이 복잡한 상호협력을 위해서 위해서 변수의 type이 변할 수도 있고, 혹은 디버깅을 위해서 변수를 접근하여 사용하는데 특정 이벤트등이 추가될 수도 있습니다. 이경우 이 class를 사용하는 소스를 모두 찾아서 고쳐야 합니다. 그게 쉬운작업만은 아니라는것을 이미 어느정도 아시리라 믿습니다. 하지만, 이미 접근자로 객체의 멤버에 접근이 제한되어 있을 경우에는, 이 문제가 아주 간단하게 해결됩니다.
실제 실무 어플리케이션을 만드는 데 있어서, 이러한 경우를 많이 겪고 있습니다.
이런경우, 이런일이 필요할때마다 클래스를 다시 만들라고는 하지 않으시겠죠?
솔직히 C++에서 C#에서처럼 접근자를 만들어줬으면 하는때가 종종 있습니다만...

PS:
제가 학부 졸업한지 몇년정도 되서, 많이 잊어먹어서 좀 틀릴지도 모릅니다.
틀린부분 있다면 가차없이 지적해주시길.. ^^

PS2:
이거 한글 깨지는거 좀 어케 할 수 없나요 ?
너무 불편합니다.

대부분의 JAVA, C#, C++ 초급서는 수준이 매우 떨여졌습니다. 객체지향의 장점을 설명하는 글에 나오는 예제들이 모두 객체지향의 단점을 설명하는 예제로 역 이용 가능했기 때문입니다. 그 후에 객체지향은 깊은 사고 끝에 추상화를 얻어낼 수 있는 것은 아닐까라 생각하고 있습니다.

사람이 사고하는 방법에는 자생 적인 부분도 있지만 환경에 영향을 받는 부분도 있어서 도구가 가진 기능들이 깊은 사고에 영향을 줄 것입니다.

사고에 영향이라는 측면에서 프로퍼티는 유해한 기능이라고 생각합니다. 잘못된 구조를 매우 쉽게 구현할 수 있게 돕는 특성이고 쉽게 사람을 현혹시키는 물건이기 때문입니다. 접근자를 만들기 힘들다면 사람들은 접근자를 더 멀리 하고 더 견고하고 추상화된 객체를 만들기 위해서 노력할 것입니다.

현실 적인 이유로 실제 코드에서 접근자가 필요한 측면도 있을 것입니다. 하지만 굳이 프로퍼티가 없다고 해서 접근자의 구현이 불가능한 것이 아닙니다. 꼭 필요한 특성이 아니라 잘못된 구현을 더 쉽게 도와주는 도구이기 때문에 C#과 Visual Baisc의 프로퍼티는 신중하지 못한 언어 설계의 결과라고 생각합니다.

익명 사용자의 이미지

Anonymous wrote:
답답하십니다..

이 정도밖에 안됩니까? 여기?

이런 문구는 문제성있는 발언 같아보입니다.
자중하시길.............

토론중에 꼭 기술적문제에의한 논쟁이 아닌 인신공격성향이 있는 말이 추가 하시는 분이 있습니다.
논쟁은 기술적인면에서 끝내세요.

토론할때 이런 문구 좀 빼시면 안돼나요?

htna의 이미지

CN wrote:
사고에 영향이라는 측면에서 프로퍼티는 유해한 기능이라고 생각합니다. 잘못된 구조를 매우 쉽게 구현할 수 있게 돕는 특성이고 쉽게 사람을 현혹시키는 물건이기 때문입니다. 접근자를 만들기 힘들다면 사람들은 접근자를 더 멀리 하고 더 견고하고 추상화된 객체를 만들기 위해서 노력할 것입니다.
현실 적인 이유로 실제 코드에서 접근자가 필요한 측면도 있을 것입니다. 하지만 굳이 프로퍼티가 없다고 해서 접근자의 구현이 불가능한 것이 아닙니다. 꼭 필요한 특성이 아니라 잘못된 구현을 더 쉽게 도와주는 도구이기 때문에 C#과 Visual Baisc의 프로퍼티는 신중하지 못한 언어 설계의 결과라고 생각합니다.

언어차원에서 접근자를 지원하는것에대해 긍정적으로 생각하는 편입니다.
프로그램도 사람이 하는일인 만큼, 노가다를 줄이면서, 직관적인으로 이해할 수 있고, 그리고 수정또한 용이하도록 도와주는 언어가 있다면 매우 훌륭한 언어모델일 것이다 라고 생각합니다.

프로퍼티가 그러한 일을 해 주는 도구가 아닌가 생각합니다.
프로퍼티는, 내부변수를 외부에 노출시키고 접근시키는데에 따른 코더의 노동을 줄여주고, 아무래도 줄이 짧아지는 결과를 보이다보니 직관적으로 이해할 수 있게 됩니다. 또한 이미 프로퍼티라는 함수(getter,setter)를 통해서 내부변수가 외부에 노출되어 있기 때문에 클래스 내부의 수정에 따른 객체를 사용하는 곳에서의 수정을 요하는 부하를 상당히 줄여준다고 생각합니다.
물론 함수를 통해 멤버에 접근하도록 모든 인터페이스를 제한하고, 그 함수의 이름앞에 get/set 이라는 인자를 주도록 하여서, 그 객체를 사용하는 입장에서 인식하게 할 수도 있지만, 어찌보면 키보드 타이핑의 시간이 늘어나는 결과가 되고, 또한 눈으로 읽어야 하는 줄의 양을 늘리는 결과가 되기도 합니다.

물론 맞습니다. 객체를 더욱 견고하고 추상화 되게 디자인 하는것이 매우 중요하긴 합니다만, 이는 프로퍼티와는 별개의 것이 아닌가 생각합니다. 객체의 추상화라면, member variable의 추상화가 아닌 객체들간의 inter-relation을 위한 operation의 추상화에 더욱 신경을 써야 하는게 아닌지...

저의경우 C++만 하는 편이라 - 개인적으로 C# 을 공부해 보기는 했지만, 실무에 적용시켜 보지는 못했습니다. - 프로퍼티를 실무에서 사용하면서 생기는 유지/보수 그리고 디자인/재활용 측면에서의 장/단점을 실제로 사용하시는 분들만큼 알지는 못합니다만. 저의 짧은 견식으로는 저렇게 생각합니다만...

다른분들은 리펙토링에 대해 어떻게 생각하십니까?
객체의 내용/속성 변경에 따른 문제를, 리펙토링으로 해결하면 되지 않을까 하는 생각이 들 수도 있을지 모르겠지만, 리펙토링도 그 나름대로의 한계를 가지고 있지 않나 합니다만...
리펙토링의 특징은 빠른 컴파일 & 빠른 결과확인을 통한 프로그램 수정에 필요한 피드백시간을 줄이는것에 크게 의존적인 면이 다분합니다.
하지만, 프로그램 규모가 커지게되면, 프로그램 전체를 컴파일하는데 6~10시간 정도 걸리게되면, 근본적인 부분에서 발생하는 문제에 대해서는 리펙토링을 할 수 없는 문제를 가지고 있다고 생각합니다.
프로그램 개발 방법에 따른 대세라고 생각이 되기는 하지만, 아직 많은 분야에 접목시키기에는 무리인 부분도 있지 않을까 합니다만..

PS:
에궁 어쩌다보니, 리펙토링까지 얘기가 나오게 되었네요..
^^;

WOW Wow!!!
Computer Science is no more about computers than astronomy is about telescopes.
-- E. W. Dijkstra

meteors의 이미지

htna wrote:
리펙토링의 특징은 빠른 컴파일 & 빠른 결과확인을 통한 프로그램 수정에 필요한 피드백시간을 줄이는것에 크게 의존적인 면이 다분합니다.
하지만, 프로그램 규모가 커지게되면, 프로그램 전체를 컴파일하는데 6~10시간 정도 걸리게되면, 근본적인 부분에서 발생하는 문제에 대해서는 리펙토링을 할 수 없는 문제를 가지고 있다고 생각합니다.

6~10시간 컴파일하는 프로그램이 뭐가 있지요? :roll:
요즘 컴퓨터는 그렇게 느리지 않을텐데요.. Windows 만들던 초창기에나 일어나던 일이 아닌가요? 또 그렇게 오래 걸린다면 최신 컴퓨터를 이용하고 또 여러대의 컴퓨터에서 일부씩 나누어서 컴파일 하고 합치는 방법을 이용하면 됩니다.
그리고 테스트 하기 위해 다 컴파일할 필요는 없게 만들면 됩니다. 소프트웨어 하나를 여러개의 라이브러리 또는 컴포넌트로 만들고 수정한 라이브러리나 컴포넌트만 바꾸면 되지요. 많이 나누어 놓으면 다시 컴파일 할 부분은 줄어듭니다.
htna의 이미지

meteors wrote:
요즘 컴퓨터는 그렇게 느리지 않을텐데요.. Windows 만들던 초창기에나 일어나던 일이 아닌가요? 또 그렇게 오래 걸린다면 최신 컴퓨터를 이용하고 또 여러대의 컴퓨터에서 일부씩 나누어서 컴파일 하고 합치는 방법을 이용하면 됩니다.
그리고 테스트 하기 위해 다 컴파일할 필요는 없게 만들면 됩니다. 소프트웨어 하나를 여러개의 라이브러리 또는 컴포넌트로 만들고 수정한 라이브러리나 컴포넌트만 바꾸면 되지요. 많이 나누어 놓으면 다시 컴파일 할 부분은 줄어듭니다.

^^;;;;
그렇게 처리할 수 있는게 있구, 여건상 그렇게 처리할 수 없는게 있습니다.

물론 분산컴퓨팅을 이용해서 컴파일 할 수도 있지만, VC에서 그게 수월하게 되는지는 좀 의심스럽군요.
물론 방법이 있는걸로 알고 있습니다만, 그것도 현실적으로 좀 문제가 되죠...
더구나 분산컴파일이 된다손 치더라도, 일단 각자 디버깅을 하기 위해선, 각자의 컴퓨터에서 컴파일을 해야하지요...

물론 모듈화란 말씀을 하실 수는 있지만, 그거야 그야말로 두 프로그램 그룹이 서로 독립적일 경우에 가능한 얘기입니다.
서로 빤히 알고있는 상태에서는 모듈을 나눈다고는 하지만, 필요하다면, 문제가 된다면, 다른사람이 만든 모듈을 건들어야 하게 됩니다.
또한 아무리 모듈을 잘 만들어놔두, dependency상 상위구조에 해당하는 놈을 건들게 되면, 하위구조 또한 모두다 컴파일이 되지요... 당연히 아시리라 생각합니다.

프로그램 개발중이 아니라, 리펙토링에서라면,
이러한 구조상에서 리펙토링을 쉽게 할 수가 없게됩니다.
물론 말단구조에 해당하는 부분은 리펙토링을 할 수가 있다고 하겠지만,
상위구조에 해당하는놈을 리펙토링 하다가는, 전체 시스템의 안전성을 확인하기 위해서 전체컴파일을 해야 하게 되는데...
좀 시간적으로 문제가 됩니다.
이 시간문제가 근본적으로 상위구조에서 리펙토링을 할 수 없게 만드는 가장 큰 문제가 됩니다...
쯔압..

프로젝트 크기는 따로 말씀드리지 않겠습니다.
음. 그거 확인하는것만도 시간 좀 잡히는 일이라..
^^;;

WOW Wow!!!
Computer Science is no more about computers than astronomy is about telescopes.
-- E. W. Dijkstra

죠커의 이미지

htna wrote:
언어차원에서 접근자를 지원하는것에대해 긍정적으로 생각하는 편입니다.
프로그램도 사람이 하는일인 만큼, 노가다를 줄이면서, 직관적인으로 이해할 수 있고, 그리고 수정또한 용이하도록 도와주는 언어가 있다면 매우 훌륭한 언어모델일 것이다 라고 생각합니다.

getter / setter를 만드게 되는 이유를 먼저 살펴봐야 합니다. 더 나은 설계가 실패했기 때문에 노가다가 생겨난 것일 겁니다. 그런 경우 그 노가다의 단계를 줄여주는 것 보다는 설계를 바꾸는 것이 더 바람직합니다. 물론 현실적인 이유로 설계를 바꾸기 힘들 경우에는 임기응변의 코드를 작성할 것을 언어가 막아야 할 이유는 없다고 봅니다만 잘못된 이유로 생겨난 노가다를 줄여줄 필요도 없다고 생각합니다.

htna wrote:
물론 맞습니다. 객체를 더욱 견고하고 추상화 되게 디자인 하는것이 매우 중요하긴 합니다만, 이는 프로퍼티와는 별개의 것이 아닌가 생각합니다. 객체의 추상화라면, member variable의 추상화가 아닌 객체들간의 inter-relation을 위한 operation의 추상화에 더욱 신경을 써야 하는게 아닌지..

필드가 외부에 노출되어서 수정되거나 참고되어야 한다면 if나 switch로 도배된 코드만큼이나 비 객체지향적이라고 생각합니다. 대부분의 노출되는 필드는 "성별의 설정"과 같이 그 상태를 다루고 있습니다. 상태는 상속을 이용하여 폴리모피즘으로 구현하는 것이 더 올바른 구현이라고 생각합니다.

htna wrote:
다른분들은 리펙토링에 대해 어떻게 생각하십니까?
객체의 내용/속성 변경에 따른 문제를, 리펙토링으로 해결하면 되지 않을까 하는 생각이 들 수도 있을지 모르겠지만, 리펙토링도 그 나름대로의 한계를 가지고 있지 않나 합니다만...
리펙토링의 특징은 빠른 컴파일 & 빠른 결과확인을 통한 프로그램 수정에 필요한 피드백시간을 줄이는것에 크게 의존적인 면이 다분합니다.
하지만, 프로그램 규모가 커지게되면, 프로그램 전체를 컴파일하는데 6~10시간 정도 걸리게되면, 근본적인 부분에서 발생하는 문제에 대해서는 리펙토링을 할 수 없는 문제를 가지고 있다고 생각합니다.
프로그램 개발 방법에 따른 대세라고 생각이 되기는 하지만, 아직 많은 분야에 접목시키기에는 무리인 부분도 있지 않을까 합니다만..

PS:
에궁 어쩌다보니, 리펙토링까지 얘기가 나오게 되었네요..
^^;

리팩토링이 빠른 컴파일 & 빠른 결과확인으로 부터 출발하는게 아니라 빠른 컴파일과 빠른 결과 확인이 리팩토링을 돕는다는 것이 더 맞겠지요. 리팩토링은 부분적인 것 부터 단계적으로 수행해나가는 것을 컨셉으로 잡고 있기 때문에 "전체"가 큰 것이 리팩토링 자체를 불가능하게 만든다고 생각하지 않습니다. "부분"의 수정이 문제가 된다면 그 프로그램의 "기능"의 추가, 수정, 버그의 수정도 이루어 질 수 없겠지요.

그런데 한가지 호기심이 드는 군요. 한번에 컴파일이 6-10 시간이나 걸리신 다면 일별 빌드는 어떤 형태로 하시는지요?

htna의 이미지

여기서부터는 좀 의미없는 논쟁이 될 듯 하군요.

저두 학생시절에 훌륭한 설계에 중요성만을 생각했습니다.
문제가 발생하게 되면, 설계를 잘못한 것이기에 소스를 고쳐야 한다는게 주된 생각이겠지만. (이와 다른 의견일수도 있구요)
여기서 프로그램 하다보니 좀 변하게되네요..
물론 설계의 중요성은 더할말이 없습니다.
하지만 그렇게 하기 힘든 경우도 많습니다.
특히 유저들과의 feedback을 하게 되는 경우에는 더욱 그러하다는것은 충분히 공감하실 듯 합니다.
물론, 개념이 꽉 잡히신 분들은, 이러한 코드를 접하기 전에는 이해하기 힘드실 듯 합니다...
저두 그랬거든요.. 와서 한동안 고생했죠...
^^;;

한번, 소스하나 수정한 다음에 컴파일타임이 1시간 이상 걸리는 문제를 리펙토링 해 보시기 바랍니다.
제대로 돌아가는지 확인하기 위해 컴파일을 하고, 실행을 하고, 다시 컴파일을 하고...
예를들어 CObject, CArchive 와 같은 계층구조를 가진 놈들을 리펙토링 한다 생각해보시기 바랍니다.
그런경우가 충분히 발생합니다.
이상과 현실은 좀 다른듯.. ^^

참고로,
.dsp 가 122개
.h 가 3500개 정도, 크기는 20~30M 입니다.
.cpp 가 3200개 정도, 크기는 50~60M 입니다.
class갯수는 좀 세기 어렵네요... struct도 있으니깐요...
소스 전체 크기는 300M정도 됩니다. 리소스 포함해서요..
그렇다고 그림등이 아주 많이 들어간것은 아닙니다.
제가알기론 이것보다 더욱 큰 프로그램도 많은걸로 알고있습니다만...
(어느사람이 VisualAssist 회사에 자신의 회사 프로젝트 크기를 알려주며 너무 커서 문제다고 올린 사람이 있었습니다. 저희와 규모가 비슷했던걸로 압니다.
VisualAssist 쪽의 대답은 그보다 10배 이상으로 훨씬 큰 규모를 가진 프로그램두 아주 많다고 대답을 했던기억이...)

컴파일은, 집에 가기전에 컴파일 합니다.
소스세이프를 통해 각자 집에가기 전에 소스를 받은 뒤, 컴파일 시켜놓고 갑니다.
다음날 아침에 새로이 작업을 하죠..
경우에따라, 귀찮은 사람들은 2~3일에 한번씩 소스세이프로 다른사람들이 업데이트 한 내용을 받습니다.. 만...

WOW Wow!!!
Computer Science is no more about computers than astronomy is about telescopes.
-- E. W. Dijkstra

meteors의 이미지

htna wrote:

상위구조에 해당하는놈을 리펙토링 하다가는, 전체 시스템의 안전성을 확인하기 위해서 전체컴파일을 해야 하게 되는데...
좀 시간적으로 문제가 됩니다.
이 시간문제가 근본적으로 상위구조에서 리펙토링을 할 수 없게 만드는 가장 큰 문제가 됩니다...

:shock:
상위 구조는 하위 구조를 mock object로 만들고 test 하면 되긴 되는데.. 처음부터 test-driven programming으로 시작되었던게 아니고 나중에 test를 만들려면 시간이 많이 들기 때문에 경영진의 결단이 필요하죠.

경영진 결단의 성공적인 예로는 게임 Sims가 있습니다. 다 refactoring을 해 냈죠. 경영진도 개발진도 Win-Win 하는 사례입니다. 경영진은 과감한 초기 투자로 나중 개발 속도를 증진시켜서 만족하고 개발진은 깨끗한 설계와 중복 코드와 불필요한 코드의 제거로 만족할만한 프로그래밍을 할 수 있었습니다.

C++에서 컴파일 속도 향상은 Large-Scale C++ Software Design(Addison-Wesley, 1996)을 참고하세요.
대규모 C++ 프로그래밍에서는 소규모처럼 프로그래밍 하면 컴파일 속도가 엄청나게 느려진다고 합니다.

htna님 회사에 따로 컴파일 속도 향상만 전담하는 인력을 둘 여유가 있을지는 모르겠지만 .. 혹시 나중에 새로운 것을 개발할때는 적용해 보세요.

htna의 이미지

meteors wrote:

상위 구조는 하위 구조를 mock object로 만들고 test 하면 되긴 되는데.. 처음부터 test-driven programming으로 시작되었던게 아니고 나중에 test를 만들려면 시간이 많이 들기 때문에 경영진의 결단이 필요하죠.

경영진 결단의 성공적인 예로는 게임 Sims가 있습니다. 다 refactoring을 해 냈죠. 경영진도 개발진도 Win-Win 하는 사례입니다. 경영진은 과감한 초기 투자로 나중 개발 속도를 증진시켜서 만족하고 개발진은 깨끗한 설계와 중복 코드와 불필요한 코드의 제거로 만족할만한 프로그래밍을 할 수 있었습니다.

C++에서 컴파일 속도 향상은 Large-Scale C++ Software Design(Addison-Wesley, 1996)을 참고하세요.
대규모 C++ 프로그래밍에서는 소규모처럼 프로그래밍 하면 컴파일 속도가 엄청나게 느려진다고 합니다.

htna님 회사에 따로 컴파일 속도 향상만 전담하는 인력을 둘 여유가 있을지는 모르겠지만 .. 혹시 나중에 새로운 것을 개발할때는 적용해 보세요.

네 맞습니다.
경영진의 결단이 필요하죠. 하지만 그러기는 힘들듯 해 보입니다.
여러가지 개발일정들이 잡혀있기 때문에, 개발인원 전체에게 몇달(리펙토링을 위해선 적어도 1달 이상의 시간이 충분이 필요하리라 봅니다)의 공백기를 주고 리펙토링 하라고 할 수 없는 실정이라고 보여집니다. 그보다, 경영진(이라고 할 수는 없겠네요, 개발 상위 책임자 정도 되려나..)이 이러한 방법론을 이해하고 필요성을 느끼는게 젤 중요하죠. 하지만 그도 쉽지는 않을듯 합니다...

Large-Scale C++ 에 대한 책은, 회사사람중 한명이 이미 대강 훑어봤던걸로 알고있습니다. 결론은 굳이 적용시키려 들지 않아도 VC에서 어느정도 해결해 준다 였지요... #pragma once 가 그 대표적인 예였습니다. 그밖에 header file의 include dependency를 줄이는게 필요하지만, 아주 기본적인 수준에서의 dependency는 이후로 정리하였습니다.

아마 새로이 프로젝트를 빌드해나가게 된다면...
그때는 좀 잘 설계할 수 있을지도 모르겠습니다.
그전에 설계하는 사람들이 얼마나 잘 설계할 수 있는가 와.
앞으로 추가될 사항을 예측해서, 앞으로 일어날 수 있는 추가사항을 쉽게 반영할 수 있도록 설계하는가가 관건인거 같습니다..

ㅋㅋ
토론내용이 저로인해 엉뚱한 방향으로 흘러간거 같네요..
근데. private보다는 protected가 쓸모없지 않나요 ?

WOW Wow!!!
Computer Science is no more about computers than astronomy is about telescopes.
-- E. W. Dijkstra

doldori의 이미지

저도 private를 protected보다 자주 쓰기는 하지만 그렇다고 protected가 쓸모없다고
할 수는 없겠는데요. 보통 생성자를 protected로 두어서 기초 클래스로만 사용되어야
한다는 의도를 나타내기도 합니다. 구현에도 관련이 있어서 추상 클래스와는 다른
성격을 갖고요. http://www.cuj.com/documents/s=8000/cujcexp1812alexandr/
protected가 적절하게 사용된 예가 나와 있습니다. (이거 얼마 전에도 링크에 걸었던
건데 또 써먹는군요. 제가 너무나 감동받아서 그런 것이니 이해해 주세요.)
코드는 ftp://ftp.cuj.com/pub/2000/cujdec2000.zip
alexandr.zip/ScopeGuard.h에 있으니 시간 나시면 훑어보시길...
또 기초 클래스의 protected 가상 함수의 의미는
http://www.cuj.com/documents/s=8000/cujcexp1812hyslop/
나와 있네요. (이것도 재탕... ^^; )

atie의 이미지

위의 손님이 쓰신 글을 보고 잠시 생각이 드는게,

같은 keyword라고 해도(예를 들어 protected) Java와 C++에서의 적용시, 의미가 다르고,
클래스 상속시, 접근자 변경의 가능 여부가 틀리고,
interface와 abstract의 조합으로 Java에서 할 수 있는 것과 C++의 virtual keyword 왜 있는지가 Java와 연관되서 이해가 된 후에

싸잡아 이 곳의 수준을 비난한 것이 아니죠?

다른 랭귀지를 쓰는 분들의 이야기를 차분히 읽어 보고 본인의 의견을 개진하길 바랍니다.

----
I paint objects as I think them, not as I see them.
atie's minipage

htna의 이미지

doldori wrote:
저도 private를 protected보다 자주 쓰기는 하지만 그렇다고 protected가 쓸모없다고
할 수는 없겠는데요. 보통 생성자를 protected로 두어서 기초 클래스로만 사용되어야
한다는 의도를 나타내기도 합니다. 구현에도 관련이 있어서 추상 클래스와는 다른
성격을 갖고요. http://www.cuj.com/documents/s=8000/cujcexp1812alexandr/
protected가 적절하게 사용된 예가 나와 있습니다. (이거 얼마 전에도 링크에 걸었던
건데 또 써먹는군요. 제가 너무나 감동받아서 그런 것이니 이해해 주세요.)
코드는 ftp://ftp.cuj.com/pub/2000/cujdec2000.zip
alexandr.zip/ScopeGuard.h에 있으니 시간 나시면 훑어보시길...
또 기초 클래스의 protected 가상 함수의 의미는
http://www.cuj.com/documents/s=8000/cujcexp1812hyslop/
나와 있네요. (이것도 재탕... ^^; )

에궁.
그사실을 잊구 있었네요.
protected constructor...
그밖에 디자인 패턴쪽에서 method를 protected로 사용하는 경우...
너무 getter/setter 쪽에 집착한것 같습니다.
하지만, member variable에 대해서 protected의 필요성은 여전히 의심이 가네요...
아예 public 이던지 아님 아예 private이던지...
package가 제공된다면 더할나위 없이 좋겠지만요..
좋은지적 감사합니다.

WOW Wow!!!
Computer Science is no more about computers than astronomy is about telescopes.
-- E. W. Dijkstra

익명 사용자의 이미지

htna wrote:
하지만, member variable에 대해서 protected의 필요성은 여전히 의심이 가네요...

상속은 해야하지 않을까요?
chadr의 이미지

변수를 private로 만들어 접근함수를 작성해 놓으면 해당 변수에대한 연산을 수행할때 누가 어디서 몇번을 접근했다는게(호출스택이나 로깅) 카운팅 할 수 있어서 디버깅시에 무지 편하더군요...

-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

girneter의 이미지

chadr wrote:
변수를 private로 만들어 접근함수를 작성해 놓으면 해당 변수에대한 연산을 수행할때 누가 어디서 몇번을 접근했다는게(호출스택이나 로깅) 카운팅 할 수 있어서 디버깅시에 무지 편하더군요...

이거 솔깃한데요.
좀 더 자세한 설명과 간단한 예제로
디버깅에 밤을 새는 불쌍한 중생들을 구제해 주심이 어떨런지요

개념없는 초딩들은 좋은 말로 할때 DC나 웃대가서 놀아라. 응?

익명 사용자의 이미지

CN wrote:

객체지향 하면 흔히 말하는 Smalltalk가 public으로만 이루어졌었던 걸로 기억합니다. :-)

객체지향적인 프로그램 설계와 견고한 프로그래밍을 위한 도구는 조금 다르다는 것에 동의합니다.

Smalltalk의 경우에는 public은 없는 것으로 알고 있습니다. 아마 기본으로 protected인 것으로 알고 있습니다.

그리고 객체지향과 견고한 프로그래밍과는 다르다는 것에는 동의합니다. early binding/late binding과 static system/dynamic system과의 차이만큼 서로의 지향점이 다르다고 생각합니다. 당연히 어느것이 더 좋다/나쁘다 라는 것도 목표가 어디에 있는가에 따라 다른 이야기가 될 것이고요.

voider의 이미지

제 생각은 철학의 차이입니다.

c++ 은 어떠한 모든 구조로의 프로그램이 가능하기 위한 언어 인것 같습니다
사용자는 자신이 좋아하는 스타일로 c++프로그램을 짜면 됩니다.

상대방의 스타일에 대해 머라 하지 않을수 있도록 c++은 방대합니다.

파이썬 같은 경우엔 파이썬 언어 설계자의 프로그래밍 스타일이 언어에
그대로 드러나 있습니다. (물론 너무나도 멋지고 훌륭합니다)
파이썬 유저는 이러한 프로그래밍 스타일에 대해 고민하지 않고도
언어 자체가 유도하는 스타일의 프로그램을 할수 있습니다.

음... 주제와 조금 맞지 않나요? :oops:

-- 아쉬운 하루 되세요 --

voider의 이미지

girneter wrote:
chadr wrote:
변수를 private로 만들어 접근함수를 작성해 놓으면 해당 변수에대한 연산을 수행할때 누가 어디서 몇번을 접근했다는게(호출스택이나 로깅) 카운팅 할 수 있어서 디버깅시에 무지 편하더군요...

이거 솔깃한데요.
좀 더 자세한 설명과 간단한 예제로
디버깅에 밤을 새는 불쌍한 중생들을 구제해 주심이 어떨런지요

간단합니다
class A {
private:
int a;
public:
int Get_a() { DEBUG_GET(a); return a; }
int Set_a(int val) { DEBUG_SET(a); return a = val; }
}

DEBUG_GET 과 DEBUG_SET 을 조정하시면 됩니다
하지만 개인적으론 귀찮음 때문에 사용하지 않습니다.(많은 분들이 저와 같은 이유로 사용하지 않으실 겁니다)

-- 아쉬운 하루 되세요 --

atie의 이미지

사용하는 언어에 따라 접근자의 의미가 다르지만, 자바로 접근자의 의미를 풀어쓰면 다음과 같습니다. 다른 점을 이해하는데 도움이 될까 싶어 써봅니다. 그리고, 다른 언어와 비교해서 깊게 알 수가 있을까 궁금하기도 합니다.

제 경우 (Java로)에는 어떻게 하면 인터페이스를 잘 만들까, protected를 어떻게 잘 활용할까에 코딩시 신경을 많이 씁니다.

Quote:
내 집에 은행 구좌가 있고, 그 구좌 안에 돈이 있는 경우를 자바로 만드다면, 우선은 이렇게 만들겠죠.

package myHouse;

public class Account {
    public int money;  // 1)
}   

여기에, 내 딸이 내 집 구좌의 돈을 가져갈 수 있는지를 가지고 접근자를 설명해 봅시다.

package myDaughter;

import myHouse.Account;

class DaughterAccount extends Account {
    void daughterWantMoney() {
        money = 1000;  // 2)
    }
}     


A - money가 1) 처럼 public이면, 2)처럼 money를 1000으로 지정하는게 됩니다. public이니 당연하겠죠.

B - 1)이 private int money이면, 2)는 꿈도 못 꿉니다. 아예 money는 쳐다 볼 수 없죠.

C - 1)이 protected int money이면, 2)가 가능합니다.

D- 1)이 그냥 int money이면, 2)는 불가능합니다.

A와 B의 경우는 쉽게 이해가 가죠. 그런데, C와 D는 왜 있을까요?

C는 다음의 경우를 막기 위해서 입니다.

package myDaughter;

import myHouse.Account;

class DaughterAccount extends Account {
    void daughterWantMoney() {
        Account newAccount = new Account();
        newAccount.money = 1000;  // 3)
    }
}    

3)이 불가능합니다. 즉, 다른 패키지에 있는 내 딸은 내 구좌의 돈을 보고 건드릴 수가 있지만, 딸이 구좌를 새로 만들어서 돈을 건드리는 것을 막기 위해서입니다. 여기서, 왜 protected라고 하는지 이해가 됩니다.

그럼, D처럼 아무 접근자 없이 기본 지정한 경우는 첫째, 다른 패키지에 있는 내 딸은 돈을 볼 수도 없게 하는 것이 C와 다른 점이고, 둘째, 다음처럼 내 집에 있는 아들은 돈을 보고 건드릴 수 있게 하는 것이 B와 다른 점입니다.

package myHouse;

class SonAccount extends Account {
    void sonWantMoney() {
        money = 1000;  // 4)  
    }
}    

4)이 되죠. 즉, 같은 패키지에서 money를 접근하도록 하는 것이 기본 지정입니다.

----
I paint objects as I think them, not as I see them.
atie's minipage

doldori의 이미지

money가 protected일 때 다음의 경우에는 어떻게 되나요?

package myDaughter; 

import myHouse.Account; 

class DaughterAccount extends Account { 
    void daughterWantMoney() { 
        Account newAccount = new Account(); 
        newAccount.money = 1000;  // 3) 
        DaughterAccount anotherAccount = new DaughterAccount();
        anotherAccount.money = 1000;  // 4)
    } 
} 

(3)은 불가능하다고 하셨는데 (4)는 어떤가요?
atie의 이미지

doldori wrote:
money가 protected일 때 다음의 경우에는 어떻게 되나요?
package myDaughter; 

import myHouse.Account; 

class DaughterAccount extends Account { 
    void daughterWantMoney() { 
        Account newAccount = new Account(); 
        newAccount.money = 1000;  // 3) 
        DaughterAccount anotherAccount = new DaughterAccount();
        anotherAccount.money = 1000;  // 4)
    } 
} 

(3)은 불가능하다고 하셨는데 (4)는 어떤가요?

4)는 됩니다. anotherAccount.money 는 myHouse.Account.money이죠. (multithread에 이 경우가 나오면 골치 좀 아프죠.)

그런데, 여기에

package myDaughter; 

import myHouse.Account; 

class DaughterAccount extends Account { 
    int money = 0; // *
    void daughterWantMoney() { 
        Account newAccount = new Account(); 
        newAccount.money = 1000;  // 3) 
        DaughterAccount anotherAccount = new DaughterAccount();
        anotherAccount.money = 1000;  // 4)
    } 
} 

//* 를 넣으면 money는 myDaughter.DaughterAccount.money가 됩니다. 당연한 이야기 인가요?

C++는 어떻게 됩니까?

----
I paint objects as I think them, not as I see them.
atie's minipage

doldori의 이미지

아, 이거 곤란하게 됐네요. 위에서는 제가 package, import, extends 등의 의미도
모르면서 짐작만으로 글을 썼습니다. 죄송합니다. ^^;
그런데 접근 권한만 따진다면 C++도 비슷한 것 같습니다.
그러니까 daughterWantMoney()는 DughterAccount의 protected 멤버에는
접근할 수 있지만 Account의 protected 멤버에는 접근할 수 없습니다. 코드로
표현하면 대충 다음과 같이 되겠습니다.

class Account
{ 
public:
    virtual ~Account();
protected:
    int money;
};

class DaughterAccount : public Account
{ 
    void daughterWantMoney()
    { 
        Account* newAccount = new Account; 
        newAccount->money = 1000;       // error
        DaughterAccount* anotherAccount = new DaughterAccount; 
        anotherAccount->money = 1000;   // ok 
    } 
};
atie의 이미지

doldori wrote:
아, 이거 곤란하게 됐네요. 위에서는 제가 package, import, extends 등의 의미도
모르면서 짐작만으로 글을 썼습니다. 죄송합니다. ^^;
그런데 접근 권한만 따진다면 C++도 비슷한 것 같습니다.
그러니까 daughterWantMoney()는 DughterAccount의 protected 멤버에는
접근할 수 있지만 Account의 protected 멤버에는 접근할 수 없습니다. 코드로
표현하면 대충 다음과 같이 되겠습니다.
class Account
{ 
public:
    virtual ~Account();
protected:
    int money;
};

class DaughterAccount : public Account
{ 
    void daughterWantMoney()
    { 
        Account* newAccount = new Account; 
        newAccount->money = 1000;       // error
        DaughterAccount* anotherAccount = new DaughterAccount; 
        anotherAccount->money = 1000;   // ok 
    } 
};

엇! 이게 차이를 알 수 있는 굉장히 좋은 예군요.

Java에서는 상속을 할 때, 접근자를 지정할 곳이 없습니다. 제가 예시한 코드에서 public class Account를 class Account로 바꾸어 보고 DaughterAccount에서의 변화를 보면 금방 어떤 의미인지를 알 수 있습니다.

그리고, virtual keyword가 없습니다. 모든 non-static 메쏘드는 항상 dynamic binding을 사용하므로 프로그래머에게 결정할 여부가 주어지지 않습니다.

대신에, Java에서는 abstract class와 interface를 가지고 하는 것이 있는데 이건 기회가 되면 나중에 쓰도록 하죠.

----
I paint objects as I think them, not as I see them.
atie's minipage

cc의 이미지

getter/setter를 쓰는 것이 encapsulate된다라는 점을 이해못하시는 분이 많은데.
단순히 data만 encapsulate되는 것이 아니라, validaion정보까지 encapsulate되는 것입니다.
public변수를 외부에서 대입하는 경우를 가정해봅시다.
validation에 대한 루틴이 객체 밖으로 드러나게 됩니다.
객체에 대한 이해가 부족했을 경우에는 잘못된 루틴이 들어갈 수도 있습니다.
그러나 setter를 만들 때에는 validation부분까지 넣습니다.
JAVA를 예를 들면 setter에서 입력값을 검사해서 적절한 Exception을 발생시키고는 합니다.