1. 상속 계층 트리에서 메서드 오버라이딩 할때 구분할 개념들


a.오버라이드 가능한 "추상" 루틴(=메서드)은 파생 클래스가 루틴의 인터페이스를 상속받지만 구현부는 상속받지

않는다는 것을 의미한다.=>설계(interface)와 구현의 분리

 

b.오버라이드 가능한 루틴은 파생 클래스가 루틴의 인터페이스의 기본 구현을 상속받으며 기본 구현을 오버라이드할

수 있다는 것을 의미한다. =>Object 클래스의 equal() , hashcode(), copy() 등을 내 클래스의 사용 목적에 맞게 재정의

하는것

 

c.오버라이드 불가능한 루틴은 파생 클래스가 루틴의 인터페이스와 기본 구현을 상속 받지만 루틴의 구현을 오버라이드

할수 없다는 것을 의미한다. =>즉 해당 인터페이스 클래스가 외부에 노출시키는 public 인터페이스(메서드)를 의미

 

(ex)

 public abstract class Base

{

a. public abstract void method;

 

b. public void method()

{

   doSomething~ 
}

 

c. public final void method()

{

   doSomething~
}


}


 

=> 인터페이스를 상속(a)받고 싶을땐 구현 상속(b)을 주의하고, 구현을 상속받고 싶을땐 인터페이스 상속을 주의하고

만약 인터페이스는 필요없고 구현만 사용하고 싶다면 상속 대신 포함(agreegacion)을 사용하라! => stratergy패턴을 의미

 

(2013/11/29 추가)

=> 메서드를 구현한다(abstract) , 메서드를 확장한다(overide). 라는 심플한 개념으로 구분이 가능할 것이다.

 

 

2.오버라이드 불가능한 멤버 루틴을 오버라이드 하지 말것 (ex) Base의 private void method()를 Child가 private void method()

=> 별개의 루틴이지만, 이름이 똑같이에 다형성인듯 착각되기 쉽기 때문

 

3.공통적으로 사용되는 인터페이스,데이터,행위를 상속트리에서 가능한 한 가자 높은 곳으로 이동시킨다

=>높이는 정도는 해당 루틴이 해당 객체의 추상화를 깰때. 음.. Dog 에 있는 eat() Tiger 에 있는 eat()는 

   Animal의 eat()으로 이동이 가능하지만, eat()을 Object클래스에 올리면 Object 클래스의 '일반적'개념이 부셔지지..

 

4.인스턴스가 하나뿐인 클래스를 의심하자

=>파생시킨 클래스가 별개의 클래스로서가 아니라 데이터로 표현될수 있나?를 고려해야 한다. is a가 아닌, has a 인지,

   이도 저도 아니라면 서로 다른 계층 트리에서 xxAble이라고 interface class를 통해 특정한 속성의 집합으로 묶을수 있다.

   단, 싱글턴은 예외이다. 동물들에 싸움 기능을 추가하고 싶다고 dog -> fightAbleDog , nonFighterAble로 파생시켜 확장

   하는 것은 미친짓. 차라리 Animal에 FighteAble 필드를 추가하거나, FighteAlbe을 인터페이스 클래스로 구현해 implements

   하거나..

 

5.파생클래스가 하나뿐인 기본 클래스를 의심하자

=>너무 앞서서 설계했다. 가능한한 현재의 작업을 분명하고 직관적이며 단순하게 만드는게 중요하다.

 

6.루틴을 오버라이드하고 파생된 루틴 내부에서는 아무것도 하지 않는 클래스들을 의심하자.

=>기본 클래스 설계의 오류를 암시한다. "is a   vs    has a "

 

7.깊은 상속 트리를 피하자

=>내 경우에 awt를 분석하고 java api의 클래스들간 관계성을 분석할때 해당 클래스가 깊은 계층 트리에 있어서 복잡성

이 심했다.

 

8.간결및 직관성 vs 디자인 패턴

=> 무조건 패턴(추상적인 설계)을 적용시켜야만 할까?


(ex)

switch( ui.Command() )

{

 case Command_OpenFile:

         OpenFile();

          break;

 

  case Command_Print:

          Print();

          break;

 

  case Command_Save:

          Save();

          break;

 

  case Command_Exit:

           Exit();

          break;

   ...

}

 

=> 이 경우에 기본 클래스를 생성하여 각 명령에 대한 다형성 DoCommand()메서드를 만들수 있다

( Command패턴 ) 하지만 위처럼 switch case간단하고 명확한 경우엔 굳이 Command패턴을

사용해 비 직관적이게 만들 필요가 없다.


9.상속 계층 트리에서 기본 클래스의 모든 데이터(멤버필드)를 protected가 아닌 private로 만들자?

=>상속은 캡슐화를 부순다(joshua bloch) 그럼으로 파생 클래스에서 기본 클래스의 특성을 접근해야

한다면 protected 접근 메서드를 대신 제공하라.  <- 개념엔 동의를 하지만, 실제 구현시 너무 귀찮아짐으로

패스


10.다중 상속은 미친짓

=>다이아몬드 상속구조와 그에 따른 메서드명 중복, 생성&소멸자의 호출순서등 너무 복잡해짐으로 무조건 동의. 

더이상 노코멘트 



1~10 정리

a.만약 다중 클래스가 데이터는 공유하지만 행위를 공유하지 않는다면, 클래스가 포함할수 있는 객체를 만든다.

=>연산은 공유하지 않고 특성만 공유할 경우(has a)


b.만약 다중 클래스가 행위는 공유하지만 데이터를 공유하지 않는다면, 공통적인 루틴들을 정의한 기본 클래스를 

상속받는다.

=>인터페이스(외부 노출 public 메서드에 대한 계약or통제) 즉, 인터페이스 클래스의 존재 의의와 개념


c.만약 다중 클래스가 데이터와 행위를 공유한다면, 공통적인 데이터와 루틴들을 정의해 기본 클래스를 상속받는다.

=>일반 베이스 클래스 or 추상 클래스의 존재 의의와 개념


d.인터페이스를 제어하기 위한 기본 클래스가 필요할 때에는 상속을 하고(인터페이스 클래스를 의미), 인터페이스를

제어하고 싶다면 포함시킨다.(stratergy패턴 = 메서드의 확장)




<멤버 함수와 데이터를 효율적으로 구현하기 위한 몇가지 지침들>


1.클래스에 가능한 한 적은 수의 루틴을 유지


2.원하지 않는 멤버 함수와 연산자들이 암시적으로 생성되지 않도록 주의

=>자바의 경우 컴파일러가 추가해주는 암시적 default 생성자및 Object클래스에서 상속 받게 되는 

copy() 참조주소 복사 , equal() 참조주소 비교 , hashCode() 참조주소를 통한 해쉬코드 등을 의미한다.

즉 내 클래스의 목적과 특성에 맞도록 재정의해야만 하고, 또한 주의해야만 한다.


3.클래스에서 호출되는 루틴의 수를 최소화

=>클래스가 타 클래스와 assciation이 많아지면 오류가 증가할 가능성이 많아지고 이것을 "팬아웃" 이란 용어로 사용


4.다른 클래스에 대한 간접 루틴 호출을 최소화("데미테르의 법칙")

=> 객체 A가 객체 B를 인스턴스화했다면, B가 제공하는 루틴은 어느 것이던 호출이 가능하지만 , B에 의해 제공되는

객체들(C,D)의 루틴은 호출하지 말아야 한다.

(ex) account.contactPerson()   vs   account.contactPerson().dayTimeContactInfo()

 

 

-(추가) 이행적으로 종속되다?  ... 고민해볼 안건..

maven(메이븐) manage 문서를 보던중,.. 메이븐 저장소는 의존 관계가 있는 아티팩트를 다운로드 하기 위하여

POM? 을 해석하여 프로젝트에 어떤 "이행 종속관계"이 있는지 판단하여 처리한다.

(ex) A->B->C   :   A->C    

5.일반적으로 클래스가 다른 클래스와 협력하는 정도를 최소화(4번을 다시 설명)

a.인스턴스화되는 객체의 수

b.인스턴스화된 객체에 대한 서로 다른 직접적인 루틴 호출의 수

c.인스턴스화된 다른 객체에 의해서 리턴되는 객체에 대한 루틴 호출의 수 



<생성자에 필요한 지침>


1.가능하다면 모든 멤버 데이터를 모든 생성자에서 초기화

=>내 경우에도 이것을 동의함. 매개변수 없는 생성자는 너무 위험하다고 느낌.(reflect를 이용해 생성할때

  클래스에 정의된 매개변수있는 생성자 타입 객체를 만드는게 가능한데.. 왜 프레임워크 들에서 단순하게 

  디폴트 생성자 타입 객체를 인스턴스화하고 거기에 invoke를 이용해 setter로 멤버 데이터를 초기화 하는진 의문임..)


2.private 생성자를 사용하여 싱글턴 속성을 구현

=>잘 알기에 패스 (단, 멀티스레드 환경을 고려할때 getInstance()의 if(instance == null) syncronized(instance) if(instance

  == null) {instance = new ClassType();} <- 이 패턴을 기억해둘것 (첫번째 if조건은 비 인스턴스화시 불필요한 연산을 

  방지하기 위한 성능 향상 목적이고, 두번째 if조건은 멀티스레드 환경을 고려한 구문임)


3.다른 사항이 증명될 때까지 얕은 복사보다 깊은 복사를 하자

=>동의함. value비교,복사는 시간은 오래 걸리지만, 객체의 독립성을 보장해줌. reference(주소)비교 복사는 시간은 빠르지만

객체의 독립성을 보장해주지 않고, 객체의 메모리상 존재만 보장해줌. 그럼으로 copy, equal, hashCode 는 기계적으로 해주자. 나중에 참조 형태로 풀어주더라도..



<클래스를 작성하는 이유>


1.실세계의 객체를 모델링


2.추상 객체들을 모델링


3.복잡성을 줄인다 

=>캡슐화&정보은닉&무엇을 public으로 노출시킬것인가 = 무엇을 private로 감출 것인가에 대한 고찰


4.복잡성을 고립시킨다.

=>클래스의 역할및 개념정의 책임의 영역 설정, 타 클래스와의 불필요한 관계 단절


5.세부적인 정보를 숨기자(3번과 동일. Interface적 의미)


6.변경의 영향을 제한할것(3,5의 정보 은닉과 동일)

=>(ex)하드웨어에 의존적인 부분(display,io등), 비지니스 규칙, 복잡한 데이터형


7.전역 데이터를 숨길것

=>클래스에서 public 으로 멤버 필드를 노출해주면 전역 데이터 처럼 사용이 가능한데.. 이것은 멀티스레드에

   안전하지 않을 뿐더러 관계되는 여러 클래스들이 전역 데이터에 의존적이게 됨


8.association에서 매개변수의 전달을 간소화

=>만약 어떤 매개변수를 여러 루틴들 사이에서 전달하고 있다면, 매개변수를 객체 데이터로 공유하는 클래스에 

이 루틴들을 포함시켜야 할 필요성이 있다는 것을 암시


9.중앙 집중 관리할것 

=>Format, Word(비지니스로직)의 설계를 reminding , 즉 Word는 여러개의 부분들을 통합해 의미 있는 업무

 를 창출하는 중앙 통제자의 역할임


=> 이해가 부족함. 코드 컴플릿2 236p.. 매우 중요한 개념 같은데.. 프레임 워크의 개념을 의미하는 것일까?


10.코드의 재사용을 도울것

=>재사용 가능성이 높은 일반적인 연산이라면 별도의 클래스로 추출하는 것이 효과적(중복 코드 방지)

   내 경운 이것을 클래스or 멤버 메서드로 뽑아내는 것만 생각했지 클래스로 추출한다는 것은 생각을 못했음.

   왜냐하면 객체지향이란, 연산의 집합이 아닌, 데이터 + 연산의 집합이기 때문.


11.프로그램군(family)를 위한 계획을 작성 (10을 다시 설명)


(ex) 수년전에 나는 보험을 파는 고객이 사용할 일련의 프로그램들을 작성하는 팀을 관리했얶다. 우리는 각 프로그

램을 작성하는 팀을 관리했었다. 우리는 각 프로그램을 고객의 보험률과 보고서 양식등에 맞추어야 했다. 하지만 프로그램의

많은 부분들이 유사했었다. 잠재적인 고객에 대한 정보를 입력하고 고객 데이터베이스에 정보를 저장하고, 보험률을 검색하고

,특정 그룹의 전체 보험료를 계산하는 클래스들이 비슷했다. 처음 프로그래밍했을 때는 석 달 정도 결렸던 것 같은데, 새로운

고객이 생겼을 때에는 새로운 고객을 위해서 새로운 클래스를 몇 개만 작성하여 나머지 코드 부분에 추가하였다.

몇일 동안 작업을 한 다음 , 소프트웨어 완성!  


=>내 이해가 부족해서 책의 내용을 그대로 옮겼음. 하지만 다수의 인스턴스를 관리하는 매니저 클래스의 연산인

   생성,삽입,조회,정렬,수정,제거,소멸은 알고 있다.


12.연관된 기능을 패키지화하자

=>정보를 숨기거나, 데이터를 공유하거나, 유연한 계획을 세울 수 없는 경우엔 관련된 기능들을 도메인 그룹으로 패키지

화 해서 묶자. 문제 발생시 전체 시스템에 파장이 적어진다. (즉 위에서 집어본 독립성과 동일한 개념)


13.특정한 리팩토링을 수행 (아직 개념이 정립이 안돼서 패스)


(ex)하나의 클래스를 두 개의 클래스로 변환하고(역할,개념적 분리?) 델리게이트(delegate=대표)를 감추고,

미들 맨 (middle man)을 제거하고, 확장 클래스를 만드는 방법으로 새로운 클래스들이 만들어진다. 


=>책의 내용 그대로 옮김(추후에 이해될듯.. 현재로선 내가 아는 범위 밖의 내용임)



<피해야할 클래스>

1.만능 클래스를 생성하지 말것

=>당연.. 코드가 더럽게 꼬이고 추후 수정도 거의 불가능


2.관련이 없는 클래스들을 제거할것

=>클래스의 위상이 아니다, 끽해봐야 내부 클래스 위상


3.동사가 따라오는 클래스를 피할것

=>다른 클래스의 루틴의 일부로



<전체 요약>

1.실세계의 객체를 모델링

2.추상객체를 모델링

3.복잡성을 줄일것

4.복잡성을 고립시킬것

5.세부적인 정보를 숨길것

6.변경의 영향을 제한할것

7.전역 데이터를 숨길것

8.매개변수의 전달을 최소화 할것

9.중앙 집중 관리할것

10.코드의 재사용을 도울것

11.프로그램군을 위한 계획을 작성할것 (이해 상당히x)

12.연관된 기능을 패키지화 할것(아주 살짝 이해)

13.특정한 리팩토링을 수행할것 (이해 전혀x)

by givingsheart 2014. 1. 1. 14:57