오늘은 폰갭 관련 좋은 교재가 있는지 확인하러 서점에 들렀었습니다.

 

대략 12시쯤 나가서 6시쯤 돌아왔는데요.. 온갖 책들의 표지만 실컷 구경하다 와버렸네요.

 

애초에 목표로 했던 폰갭 관련 도서의 경우.. 제 눈에는 "난 폰갭으로 뭔가 만들었습니다. 그러니

내 코드 한번 따라 쳐보세요" 식이라 영 구미가 안당겼습니다.

 

그다음으로 생각했던게.. spring 관련 교재였는데요.. 저는 api문서처럼 참조하는 형식의 레퍼런스

북이 아닌, 개념 이해부터 다양한 소스까지 포함된 책을 찾다보니.. 몇몇 책이 탐지 되었습니다.

 

결국 "프로 스프링3<에이콘출판>" "스프링 MVC 프로그래밍<위키북스>" 두 책을 점찍어 왔습니다.

 

이 책 괜찮을까요?  궁금합니다~

 

 

ps.오는 길에 중고 서점에 들러 code complete2 , jsp1.2버전의 java server pages란 책을 구매해

왔는데.. jsp 1.2....

 

주말에 the c++ programming language란 책을 붙잡고 있는 중인데.. 너무 어렵습니다. OTL

 

어쩌다 보니 잡담 형식이 되었네요. 흠.. 뭔가 의미 있는 정보를 넣어야 할텐데..

 

 

 

 

상위클래스타입의 참조형 변수에 하위클래스타입의 객체를 보관할수 있다는 문제에 대해 대충 고찰해 봅니다.

 

 

사용해보니 완전 편하지요? A타입,B타입,C타입 따로 배열을 만들어 보관할 필요 없이. A,B,C,의 상위 클래스

인 Base타입 배열 하나로 보관하다니.. 얼마나 행복합니까. 물론 상속(일반화&구체화 => A is a Base, B is a Base..)

라는 개념은 이해하는 걸로 전제합니다.

 

 

상위 클래스 , 하위 클래스 구분부터 합니다.

1.포함하는 멤버필드,멤버 메서드는 :상위 클래스 <= 하위 클래스 로서 한마디로 하위클래스가 덩치는 더 크거나 같습니다.

 

2.혼란이 있을수 있는 부분이 우리는 큰 자료형에 작은 자료형을 넣을때 별다른 문제가 없다고 기억합니다.

  double d = 10.f;    

 

3.하위클래스의 덩치가 크니까 상위 클래스를 넣어도 별 문제가 없어 보이지만 한가지 고려할 부분이 있습니다.

 

 

(데이터의 타입 선언(자바에선 불필요한듯?),정의,메모리 할당,초기화에 대해 설명을 드릴까 고민해 봤지만,

처음부터 개념을 잡아주려면 시간이 많이 걸릴듯 하여 생략합니다. 서적 참고 + 개별적으로 검색)

 

 

4.프리미티브타입 vs 레퍼런스타입 : 참조(레퍼런스) 타입의 변수는 메모리상의 주소 0x11212124 를 기억하기

위한 변수 입니다. Person이란 클래스 타입이 있고, 그것의 메모리상 주소를 가리킬수 있는 Person p;에서

p가 주소를 담는 참조변수입니다. (new를 통해 실제 Person 크기만큼의 메모리를 할당하고 그 주소를 레퍼런스

타입 변수명 p에 기억시키는 것은 별개의 과정입니다. 아 글고.. 프리미티브라도 배열타입은 레퍼런스타입과 같습

니다. int a; Person p; 등의 변수명은 실제 메모리 공간의 주소를 사람이 인식하고 다루기 쉽게 연결해줍니다.)

 

프리미티브형은 타입 별로 메모리상 차지하는 공간에 차이가 있습니다. 1byte,2byte,4byte..

 

레퍼런스타입은 1,2,4byte 처럼 차이가 있지 않습니다. 자바에선 4byte로 고정입니다.(64비트 운영체제에서도

그런진 모르겠습니다)

 

5.3으로 되돌아가 보면.. 결국 상위클래스와 하위클래스의 메모리(힙영역)상 위치를 가리키는 참조변수는

크기가 4byte로 동일합니다. 그럼으로 상위클래스 타입과 하위 클래스 타입간에 형변환이 가능합니다.

 

6.2에서 거론한 프리미티브간의 형변환과 레퍼런스타입중 계층트리(상속관계) 형변환은 의미상 차이가 있습니다.

데이터 사이즈가 큰쪽 vs 작은쪽      <----->   개념상 상위타입(사람) vs 하위타입(여자or남자)

 

7.자바 컴파일러는 타입간의 계층트리에 대해 많은걸 알고 있습니다. 우리가 타입들을 선언+구현=정의해주고

타입간에 관계를 알려줬기 때문이죠. extends, implements .. 그래서 6의 두가지 형변환(크기상 형변환 vs 다형적

의미의 형변환)이 컴파일러 입장에선 of course입니다.

 

8.그럼으로 형변환을 허용해주고 얼핏 크기가 달라보이는데도 하나의 컨테이너(배열= 동일한 데이터 타입의 집합)

에 담을수 있는 것입니다.

 

long l = 10(int); <-- 문제 없습니다.(물론 컴파일 오류는 뜨겠지만;;)

int i = 10L; <--문제가 있습니다. 사이즈가 큰 타입을 작은 타입에 넣어주면 데이터 손실이 있을수 있기에 명시적인

                    형변환 int i = (int)10L; 이 필요합니다. 

Base base = new Child(); <--  문제 없습니다.(개념상 상위 타입에 하위 타입을 넣었음으로)

Child child = new Base(); <--  문제가 있습니다.(데이터 손실은 없지만 마찬가지로 명시적인 형변환이 필요합니다.)

 

=>제가 틀린 부분이 있을지도 모르겠습니다만, 하여간 시간을 투자해 지식을 공유했습니다.(제가 책볼 시간을 쪼개서)

그럼으로 이제 더 이상 제가 아는 것을 남기는 설레발은 안떨겠습니다.

 

이상입니다. 이따 봅시다. 굿나잇~

by givingsheart 2014. 1. 1. 15:00

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