1. 객체지향언어
   

1.1 객체지향언어의 역사

요즘은 컴퓨터의 눈부신 발전으로 활용 폭이 넓고 다양해져서 컴퓨터가 사용되지 않는 분야가 없을 정도지만, 초창기에는 주로 과학실험이나 미사일 발사실험과 같은 모의실험(Simulation)을 목적으로 사용되었다.
이 시절의 과학자들은 모의실험을 위해 실제 세계와 유사한 가상 세계를 컴퓨터 속에 구현하고자 노력하였으며, 이러한 노력은 객체지향이론을 탄생시켰다.
객체지향이론의 기본 개념은 '실제 세계는 사물(객체)로 이루어져 있으며, 발생하는 모든 사건들은 사물간의 상호작용이다.'라는 것이다.

실제 사물의 속성과 기능을 분석한 다음, 데이터(변수)와 함수로 정의함으로써 실제 세계를 컴퓨터 속에 옮겨 놓은 듯한 가상세계를 구현하고 이 가상세계에서 모의실험을 함으로써 많은 시간과 비용을 절약할 수 있었다.
객체지향이론은 상속, 캡슐화, 추상화 개념을 중심으로 점차 구체적으로 발전되었으며, 1960년대 중반에 객체지향이론을 프로그래밍언어에 적용한 Simula라는 최초의 객체지향언어가 탄생하였다.
그 당시 FORTRAN이나 COBOL과 같은 절차적 언어들이 주류를 이루었으며, 객체지향언어는 널리 사용되지 못하고 있었다.
1980년대 중반에 C++을 비롯하여 많은 수의 객체지향언어가 발표되면서, 객체지향언어가 본격적으로 개발자들의 관심을 끌기 시작하였지만 여전히 사용자 층이 넓지 못했다.
그러나 프로그램의 규모가 점점 커지고 사용자들의 요구가 빠르게 변화해가는 상황을 절차적언어로는 극복하기 어렵다는 한계를 느끼고 객체지향언어를 이용한 개발방법론이 대안으로 떠오르게 되면서 조금씩 입지를 넓혀가고 있었다.
자바가 1995년에 발표되고 1990년대 말에 인터넷의 발전과 함께 크게 유행하면서 객체지향언어는 이제 프로그래밍의 주류로 자리잡았다.


1.2 객체지향언어

객체지향언어는 기존의 프로그래밍언어와 다른 전혀 새로운 것이 아니라, 기존의 프로그래밍 언어에 몇가지 새로운 규칙을 추가한 보다 발전된 형태의 것이다. 이러한 규칙들을 이용해서 코드간에 서로 관계를 맺어 줌으로써 보다 유기적으로 프로그램을 구성하는 것이 가능해졌다. 기존의 프로그래밍 언어에 익숙한 사람이라면 자바의 객체지향적인 부분만 새로 배우면 될 것이다. 다만 절차적언어에 익숙한 프로그래밍 습관을 객체지향적으로 바꾸도록 노력해야할 것이다.

객체지향언어의 주요특징은 다음과 같다.


1. 코드의 재사용성이 높다.
     - 새로운 코드를 작성할 때 기존의 코드를 이용하여 쉽게 작성할 수 있다.
2. 코드의 관리가 용이하다.
     - 코드간의 관계를 이용해서 적은 노력으로 쉽게 코드를 변경할 수 있다.
3. 신뢰성이 높은 프로그래밍을 가능하게 한다.
     - 제어자와 메서드를 이용해서 데이터를 보호하고 올바른 값을 유지하도록 하며,
       코드의 중복을 제거하여 코드의 불일치로 인한 오동작을 방지할 수 있다.



객체지향언어의 가장 큰 장점은 '코드의 재사용성이 높고 유지보수가 용이하다.'는 것이다. 이러한 객체지향언어의 장점은 프로그램의 개발과 유지보수에 드는 시간과 비용을 획기적으로 개선하였다.
앞으로 상속, 다형성과 같은 객체지향개념을 학습할 때 재사용성과 유지보수 그리고 코드의 중복 제거, 이 세가지 관점에서 보면 보다 쉽게 이해할 수 있을 것이다.

객체지향 프로그래밍은 프로그래머에게 거시적 관점에서 설계할 수 있는 능력을 요구하기 때문에 객체지향개념을 이해했다 하더라도 자바의 객체지향적 장점들을 충분히 활용한 프로그램을 작성하기란 쉽지 않을 것이다.
너무 객체지향개념에 얽매여서 고민하기 보다는 일단 프로그램을 기능적으로 완성한 다음 어떻게 하면 보다 객체지향적으로 코드를 개선할 수 있는가에 대해서 고민하여 점차 개선해 나가는 것이 좋다.
이러한 경험들이 축적되어야 프로그램을 객체지향적으로 설계할 수 있는 능력이 길러지는 것이지 처음부터 이론을 많이 안다고 해서 좋은 설계를 할 수 있는 것은 아니다.
특히 프로그래밍에 익숙하지 않다면 객체지향개념 보다는 연산자와 조건문과 같은 프로그래밍언어의 기본적인 요소들에 먼저 익숙해질 수 있도록 간단한 예제들을 많이 작성해 보는 것이 좋다.




   2. 클래스와 객체
   

2.1 클래스와 객체의 정의와 용도

클래스란 '객체를 정의해놓은 것.' 또는 클래스는 '객체의 설계도 또는 틀'이라고 정의할 수 있다. 클래스는 객체를 생성하는데 사용되며, 객체는 클래스에 정의된 대로 생성된다. 


클래스의 정의 - 클래스란 객체를 정의해 놓은것이다.
클래스의 용도 - 클래스는 객체를 생성하는데 사용된다.


객체의 사전적인 정의는, '실제로 존재하는 것'이다. 우리가 주변에서 볼 수 있는 책상, 의자, 자동차와 같은 사물들이 곧 객체이다. 객체지향이론에서는 사물과 같은 유형적인 것뿐만 아니라, 개념이나 논리와 같은 무형적인 것들도 객체로 간주한다. 
프로그래밍에서의 객체는 클래스에 정의된 내용대로 메모리에 생성된 것을 뜻한다. 


객체의 정의 - 실제로 존재하는것. 사물 또는 개념
객체의 용도 - 객체가 가지고 있는 기능과 속성에 따라 다름

유형의 객체 - 책상, 의자, 자동차, TV와 같은 사물
무형의 객체 - 수학공식, 프로그램 에러와 같은 논리나 개념


클래스와 객체의 관계를 우리가 살고 있는 실생활에서 예를 들면, 제품 설계도와 제품과의 관계라고 할 수 있다. 예를 들면, TV설계도(클래스)는 TV라는 제품(객체)을 정의한 것이며, TV(객체)를 만드는데 사용된다. 
또한 클래스는 단지 객체를 생성하는데 사용될 뿐이지 객체 그 자체는 아니다. 우리가 원하는 기능의 객체를 사용하기 위해서는 먼저 클래스로부터 객체를 생성하는 과정이 선행되어야 한다. 
우리가 TV를 보기 위해서는, TV(객체)가 필요한 것이지 TV설계도(클래스)가 필요한 것은 아니며, TV설계도(클래스)는 단지 TV라는 제품(객체)을 만드는데만 사용될 뿐이다. 그리고 TV설계도를 통해 TV가 만들어진 후에야 사용할 수 있는 것이다. 
프로그래밍에서는 먼저 클래스를 작성한 다음, 클래스로부터 객체를 생성하여 사용한다.

[참고]객체를 사용한다는 것은 객체가 가지고 있는 속성과 기능을 사용한다는 뜻이다. 

 

클래스를 정의하고 클래스를 통해 객체를 생성하는 이유는 설계도를 통해서 제품을 만드는 이유와 같다. 하나의 설계도만 잘 만들어 놓으면 제품을 만드는 일이 쉬워진다. 제품을 만들 때마다 매번 고민할 필요없이 설계도 대로만 만들면 되기 때문이다. 
설계도 없이 제품을 만든다고 생각해보라. 복잡한 제품일 수록 설계도 없이 제품을 만든다는 것은 상상할 수도 없을 것이다. 
이와 마찬가지로 클래스를 한번만 잘 만들어 놓기만 하면, 매번 객체를 생성할 때마다 어떻게 객체를 만들어야 할지를 고민하지 않아도 된다. 그냥 클래스로부터 객체를 생성해서 사용하기만 하면 되는 것이다. 
J2SDK(Java2 Standard Development Kit)에서는 프로그래밍을 위해 많은 수의 유용한 클래스(Java API)를 기본적으로 제공하고 있으며, 우리는 이 클래스들을 이용해서 원하는 기능의 프로그램을 보다 쉽게 작성할 수 있다. 



2.2 객체와 인스턴스

클래스로부터 객체를 만드는 과정을 클래스의 인스턴스화(instantiate)라고 하며, 어떤 클래스로부터 만들어진 객체를 그 클래스의 인스턴스(instance)라고 한다. 

예를 들면, Tv클래스로부터 만들어진 객체를 Tv클래스의 인스턴스라고 한다. 결국 인스턴스는 객체와 같은 의미이지만, 객체는 모든 인스턴스를 대표하는 포괄적인 의미를 갖고 있으며, 인스턴스는 어떤 클래스로부터 만들어진 것인지를 강조하는 보다 구체적인 의미를 갖고 있다. 
예를 들면, '책상은 인스턴스다.'라고 하기 보다는 '책상은 객체다.'라는 쪽이, '책상은 책상 클래스의 객체이다.'라고 하기 보다는 '책상은 책상 클래스의 인스턴스다.'라고 하는 것이 더 자연스럽다. 

인스턴스와 객체는 같은 의미이므로 두 용어의 사용을 엄격히 구분지을 필요는 없지만, 위의 예에서 본 것과 같이 문맥에 따라 구별하여 사용하는 것이 좋다. 

 


2.3 객체의 구성요소 - 속성과 기능


객체는 속성과 기능, 두 종류의 구성요소로 이루어져 있으며, 일반적으로 객체는 다수의 속성과 다수의 기능을 갖는다. 즉, 객체는 속성과 기능의 집합이라고 할 수 있다. 그리고, 객체가 가지고 있는 속성과 기능을 그 객체의 멤버(구성원, member)라 한다. 

 

클래스란 객체를 정의한 것이므로 클래스에는 객체의 모든 속성과 기능이 정의되어있다. 클래스로부터 객체를 생성하면, 클래스에 정의된 속성과 기능을 가진 객체가 만들어지는 것이다. 

보다 쉽게 이해할 수 있도록 TV를 예로 들어보자. TV의 속성으로는 전원상태, 크기, 길이, 높이, 색상, 볼륨, 채널과 같은 것들이 있으며, 기능으로는 켜기, 끄기, 볼륨 높이기, 채널 변경하기 등이 있다. 

 

객체지향 프로그래밍에서는 속성과 기능을 각각 변수와 함수로 표현한다. 



속성(property) → 멤버변수(variable)
기능(function) → 메서드(method)

채널 → int channel
채널 높이기 → channelUp() { ... }



위에서 분석한 내용을 토대로 Tv클래스를 만들어 보면 다음과 같다. 


class Tv { 
     // Tv의 속성(멤버변수) 
     String color;             // 색상 
     boolean power;       // 전원상태(on/off) 
     int channel;             // 채널 

     // Tv의 기능(메서드) 
     void power() {      power = !power; }      /* TV를 켜거나 끄는 기능을 하는 메서드 */ 
     void channelUp() {     ++channel; }       /* TV의 채널을 높이는 기능을 하는 메서드 */
     void channelDown() {    --channel; }     /* TV의 채널을 낮추는 기능을 하는 메서드 */ 



[참고] 멤버변수와 메서드를 선언하는데 있어서 순서는 관계없지만, 일반적으로 메서드보다는 멤버변수를 먼저 선언하고 멤버변수는 멤버변수끼리 메서드는 메서드끼리 모아 놓는 것이 일반적이다. 

실제 TV가 갖는 기능과 속성은 이 외에도 더 있지만, 프로그래밍에 필요한 속성과 기능만을 선택하여 클래스를 작성하면 된다.

각 변수의 자료형은, 속성의 값에 알맞은 것을 선택해야한다. 전원상태(power)의 경우, on과 off 두 가지 값을 가질 수 있으므로 boolean형으로 선언했다. 

[알아두면 좋아요]
power()의 power = !power;문은 power의 값이 true면 false로, false면 true로 변경하는 일을 한다. power의 값에 관계없이 항상 반대의 값으로 변경해주면 되므로 굳이 if문을 사용할 필요가 없다. 참고로 if문을 사용하여 코드를 작성하면 다음과 같다. 

      if (power) { 
          power = false; 
     } else { 
          power = true; 
     } 




2.4 인스턴스의 생성과 사용

Tv클래스를 완성했으니, 이제는 Tv클래스의 인스턴스를 만들어서 사용해 보도록 하자. 클래스로부터 인스턴스를 생성하는 방법은 여러 가지가 있지만 일반적으로는 다음과 같이 한다. 


클래스명 변수명;      // 클래스의 객체를 참조하기 위한 참조변수를 선언한다. 
변수명 = new 클래스명(); // 클래스의 객체를 생성 후, 객체의 주소를 참조변수에 저장한다. 

Tv t;                   // Tv클래스 타입의 참조변수 t를 선언 
t = new Tv();       // Tv인스턴스를 생성한 후, 생성된 Tv인스턴스의 주소를 t에 저장한다. 


[예제6-1] TvTest.java


class Tv { 
     
// Tv의 속성(멤버변수) 
     
String color;             // 색상 
     
boolean power;       // 전원상태(on/off) 
     
int channel;             // 채널 

     
// Tv의 기능(메서드) 
     
void power() {      power = !power; }      /* TV를 켜거나 끄는 기능을 하는 메서드 */ 
     
void channelUp() {     ++channel; }       /* TV의 채널을 높이는 기능을 하는 메서드 */
     void channelDown() {    --channel; }     /* TV의 채널을 낮추는 기능을 하는 메서드 */ 
}

 

class TvTest { 
      public static void main(String args[]) { 
            Tv t;                         // Tv인스턴스를 참조하기 위한 변수 t를 선언       
            t = new Tv();             // Tv인스턴스를 생성한다. 
            t.channel = 7;             // Tv인스턴스의 멤버변수 channel의 값을 7로 한다. 
            t.channelDown();             // Tv인스턴스의 메서드 channelDown()을 호출한다. 
            System.out.println("현재 채널은 " + t.channel + " 입니다."); 
      } 

[실행결과]
현재 채널은 6 입니다. 

위의 예제는 Tv클래스로부터 인스턴스를 생성하고, 인스턴스의 속성(channel)과 함수(channelDown())를 사용하는 방법을 보여 주는 것이다. 예제를 그림과 함께 한 줄 씩 살펴보도록 하자. 

1. Tv t; 
Tv클래스 타입의 참조변수 t를 선언한다. 메모리에 참조변수 t를 위한 공간이 마련된다. 



2. t = new Tv() 
연산자 new에 의해 Tv클래스의 인스턴스가 메모리의 빈 공간에 생성된다. 주소가 0x100인 곳에 생성되었다고 가정하자. 이 때, 멤버변수는 각 자료형에 해당하는 기본값으로 초기화 된다. 
color는 참조형이므로 null로, power는 boolean이므로 false로, 그리고 channel은 int이므로 0으로 초기화 된다. 

 


그 다음에는 대입연산자(=)에 의해서 생성된 객체의 주소값이 참조변수 t에 저장된다. 이제는 참조변수 t를 통해 Tv인스턴스에 접근할 수 있다. 인스턴스를 다루기 위해서는 참조변수가 반드시 필요하다. 

 

[참고]위 그림에서의 화살표는 참조변수 t가 Tv인스턴스를 참조하고 있다는 것을 알기 쉽게 하기 위해 추가한 상징적인 것이다. 이 때, 참조변수 t가 Tv인스턴스를 '가리키고 있다' 또는 '참조하고 있다'라고 한다. 

3. t.channel = 7 ; 
참조변수 t에 저장된 주소에 있는 인스턴스의 멤버변수 channel에 7을 저장한다. 여기서 알 수 있는 것처럼, 인스턴스의 멤버변수(속성)를 사용하려면 '참조변수.멤버변수'와 같이 하면 된다. 

 

4. t.channelDown(); 
참조변수 t가 참조하고 있는 Tv인스턴스의 channelDown메서드를 호출한다. channelDown메서드는 멤버변수 channel에 저장되어 있는 값을 1감소시킨다. 

void channelDown() {       --channel;             } 

channelDown()에 의해서 channel의 값은 7에서 6이 된다. 

 

5. System.out.println("현재 채널은 " + t.channel + " 입니다."); 
참조변수 t가 참조하고 있는 Tv인스턴스의 멤버변수 channel에 저장되어 있는 값을 출력한다. 현재 channel의 값은 6이므로 '현재 채널은 6 입니다.'가 화면에 출력된다. 

인스턴스와 참조변수의 관계는 마치 우리가 일상생활에서 사용하는 TV와 TV리모콘의 관계와 같다. TV리모콘(참조변수)을 사용하여 TV(인스턴스)를 다루기 때문이다. 다른 점이라면, 인스턴스는 오직 참조변수를 통해서만 다룰 수 있다는 것이다. 
그리고, TV를 사용하려면 TV 리모콘을 사용해야하고, 에어콘을 사용하려면, 에어콘 리모콘을 사용해야하는 것처럼, Tv인스턴스를 사용하려면, Tv클래스 타입의 참조변수가 필요한 것이다. 

[예제6-2] TvTest2.java

class TvTest2 { 
      public static void main(String args[]) { 
            Tv t1 = new Tv(); 
            Tv t2 = new Tv(); 
            System.out.println("t1의 channel값은 " + t1.channel + "입니다."); 
            System.out.println("t2의 channel값은 " + t2.channel + "입니다."); 

            t1.channel = 7;       // channel 값을 7으로 한다. 
            System.out.println("t1의 channel값을 7로 변경하였습니다."); 

            System.out.println("t1의 channel값은 " + t1.channel + "입니다."); 
            System.out.println("t2의 channel값은 " + t2.channel + "입니다."); 
      } 

[실행결과]
t1의 channel값은 0입니다. 
t2의 channel값은 0입니다. 
t1의 channel값을 7로 변경하였습니다. 
t1의 channel값은 7입니다. 
t2의 channel값은 0입니다. 

위의 예제는 Tv클래스의 인스턴스 t1과 t2를 생성한 후에, 인스턴스 t1의 멤버변수인 channel의 값을 변경하였다. 
[참고] 참조변수 t1이 가리키고(참조하고) 있는 인스턴스를 간단히 인스턴스 t1이라고 했다. 

1. Tv t1 = new Tv(); 
    Tv t2 = new Tv();
 

 


2. t1.channel = 7; // 참조변수 t1이 가리키고 있는 인스턴스의 멤버변수 channel의 값을 7로 한다. 

 

같은 클래스로부터 생성되었을지라도 각 인스턴스들의 속성(멤버변수)은 서로 다른 값을 유지할 수 있으며, 메서드의 내용은 모든 인스턴스에 대해 동일하다. 

[예제6-3] TvTest3.java

class TvTest3 { 
      public static void main(String args[]) { 
            Tv t1 = new Tv(); 
            Tv t2 = new Tv(); 
            System.out.println("t1의 channel값은 " + t1.channel + "입니다."); 
            System.out.println("t2의 channel값은 " + t2.channel + "입니다."); 

            t2 = t1;             // t1이 저장하고 있는 값(주소)을 t2에 저장한다. 
            t1.channel = 7;       // channel 값을 7로 한다. 
            System.out.println("t1의 channel값을 7로 변경하였습니다."); 

            System.out.println("t1의 channel값은 " + t1.channel + "입니다."); 
            System.out.println("t2의 channel값은 " + t2.channel + "입니다."); 
      } 

[실행결과]
t1의 channel값은 0입니다. 
t2의 channel값은 0입니다. 
t1의 channel값을 7로 변경하였습니다. 
t1의 channel값은 7입니다. 
t2의 channel값은 7입니다. 

1. Tv t1 = new Tv(); 
    Tv t2 = new Tv();
 

 


2. t2 = t1;             // t1이 저장하고 있는 값(주소)을 t2에 저장한다. 

t1은 참조변수이므로, 인스턴스의 주소를 저장하고 있다. 이 문장이 수행되면, t2가 가지고 있던 값은 잃어버리게 되고, t1에 저장되어 있던 값이 t2에 저장되게 된다. 그렇게 되면, t2 역시 t1이 참조하고 있던 인스턴스를 같이 참조하게 되고, t2가 원래 참조하고 있던 인스턴스는 더 이상 사용할 수 없게 된다. 

[참고]자신을 참조하고 있는 참조변수가 하나도 없는 인스턴스는 더 이상 사용되어질 수 없으므로 가비지 컬렉터(Garbage Collector)에 의해서 자동적으로 메모리에서 제거된다. 




3. t1.channel = 7;       // channel 값을 7로 한다. 

 

4. System.out.println("t1의 channel값은 " + t1.channel + "입니다."); 
    System.out.println("t2의 channel값은 " + t2.channel + "입니다."); 

이제 t1, t2 모두 같은 Tv클래스의 인스턴스를 가리키고 있기 때문에, t1.channel의 값과 t2.channel의 값은 7이며 다음과 같은 결과가 화면에 출력된다. 


t1의 channel값은 7입니다. 
t2의 channel값은 7입니다. 


이 예제에서 알 수 있듯이, 참조변수에는 하나의 값(주소)만이 저장될 수 있으므로 둘 이상의 참조변수가 하나의 인스턴스를 가리키는(참조하는) 것은 가능하지만 하나의 참조변수로 여러 개의 인스턴스를 가리키는 것은 가능하지 않다. 





2.5 클래스의 또 다른 정의

클래스는 '객체를 생성하기 위한 틀'이며 '클래스는 속성과 기능으로 정의되어있다.'고 했다. 이것은 객체지향이론의 관점에서 내린 정의이고, 이번엔 프로그래밍적인 관점에서 클래스의 정의와 의미를 살펴보도록 하자.

1. 클래스 - 데이터와 함수의 결합

프로그래밍언어에서 데이터 처리를 위한 데이터 저장형태의 발전과정은 다음과 같다.





1. 변수 - 하나의 데이터를 저장할 수 있는 공간
2. 배열 - 같은 종류의 여러 데이터를 하나의 집합으로 저장할 수 있는 공간
3. 구조체 - 서로 관련된 여러 데이터를 종류에 관계없이 하나의 집합으로 저장할 수 있는 공간
4. 클래스 - 데이터와 함수의 결합(구조체 + 함수)


하나의 데이터를 저장하기 위해 변수를, 그리고 같은 종류의 데이터를 보다 효율적으로 다루기 위해서 배열이라는 개념을 도입했으며, 후에는 구조체(structure)가 등장하여 자료형의 종류에 상관없이 서로 관계가 깊은 변수들을 하나로 묶어서 다룰 수 있도록 했다.
그동안 데이터와 함수가 서로 관계가 없는 것처럼 데이터는 데이터끼리, 함수는 함수끼리 따로 다루어져 왔지만, 사실 함수는 주로 데이터를 가지고 작업을 하기 때문에 많은 경우에 있어서 데이터와 함수는 관계가 깊다.

그래서 자바와 같은 객체지향언어에서는 변수(데이터)와 함수를 하나의 클래스에 정의하여 서로 관계가 깊은 변수와 함수들을 함께 다룰 수 있게 했다.
서로 관련된 변수들을 정의하고 이들에 대한 작업을 수행하는 함수들을 함께 정의한 것이 바로 클래스이다.

C언어에서는 문자열을 문자의 배열로 다루지만, 자바에서는 String이라는 클래스로 문자열을 다룬다. 문자열을 단순히 문자의 배열로 정의하지 않고 클래스로 정의한 이유는 문자열과 문자열을 다루는데 필요한 함수들을 함께 묶기 위해서이다.


public final class String implements java.io.SerializableComparable { 
      private char[] value;       // 문자열을 저장하기 위한 공간 
      public String replace(char oldChar, char newChar) { 
            ... 
            char[] val = value;       // 같은 클래스 내의 변수를 사용해서 작업을 한다. 
            ... 
      } 
            ... 



이 코드는 String클래스의 실제 소스의 일부이다. 클래스 내부에 value라는 문자형 배열이 선언되어 있고, 문자열을 다루는 데 필요한 함수들을 함께 정의해 놓았다. 문자열의 일부를 뽑아낸다던가 문자열의 길이를 알아내는 함수들은 항상 문자열을 작업대상으로 필요로 하기 때문에 문자열과 깊은 관계에 있으므로 함께 정의하였다.
이렇게 함으로써 변수와 함수가 서로 유기적으로 연결되어 작업이 간단하고 명료해 진다.



2. 클래스 - 사용자정의 타입(User-defined Type)

프로그래밍언어에서 제공하는 자료형(Primitive type)외에 프로그래머가 서로 관련된 변수들을 묶어서 하나의 타입으로 새로 추가하는 것을 사용자정의 타입(User-defined type)이라고 한다.
많은 프로그래밍언어에서 사용자정의 타입을 정의할 수 있는 방법을 제공하고 있으며, 자바와 같은 객체지향언어에서는 클래스가 곧 사용자 정의 타입이다. 기본형의 개수는 8개로 정해져 있지만 참조형의 개수가 정해져 있지 않은 이유는 이처럼 프로그래머가 새로운 타입을 추가할 수 있기 때문이다. 
시간을 표현하기 위해서 다음과 같이 3개의 변수를 선언할 수 있다.


int hour;             // 시간을 표현하기 위한 변수 
int minute;             // 분을 표현하기 위한 변수 
float second;    // 초를 표현하기 위한 변수, 백분의 일초까지 표현하기 위해 float로 했다. 


만일 3개의 시간을 다뤄야 한다면 다음과 같이 해야 할 것이다. 


int hour1, hour2, hour3; 
int minute1, minute2, minute3; 
float second1, second2, second3; 


이처럼, 다뤄야 하는 시간의 개수가 늘어날 때마다 시, 분, 초를 위한 변수를 추가해줘야 하는데 다뤄야 하는 데이터의 개수가 많으면 이런 식으로는 곤란하다. 


int[] hour = new int[3]; 
int[] minute; = new int[3]; 
float[] second; = new float[3]; 


배열로 처리하면 다뤄야 하는 시간 데이터의 개수가 늘어나더라도 배열의 크기만 변경해주면 되므로, 변수를 매번 새로 선언해줘야 하는 불편함과 복잡함은 없어졌다. 그러나 하나의 시간을 구성하는 시, 분, 초가 서로 분리되어 있기 때문에 프로그램 수행과정에서 시, 분, 초가 따로 뒤섞여서 올바르지 않은 데이터가 될 가능성이 있다. 이런 경우 시, 분, 초를 하나로 묶는 사용자정의 타입, 즉 클래스를 정의하여 사용해야한다. 


class Time { 
      int hour; 
      int minute; 
      float second; 



시, 분, 초를 저장히기 위한 세 변수를 멤버변수로 갖는 Time클래스를 정의하였다. 새로 작성된 사용자정의 타입인 Time클래스를 사용해서 코드를 변경하면 다음과 같다. 

 

이제 시, 분, 초가 하나의 단위로 묶어서 다루어지기 때문에 다른 시간 데이터와 섞이는 일은 없겠지만, 시간 데이터에는 다음과 같은 추가적인 제약조건이 있다.


1. 시, 분, 초는 모두 0보다 커야한다. 
2. 시의 범위는 0~23, 분과 초의 범위는 0~59이다.


이러한 조건들이 모두 프로그램 코드에 반영될 때, 보다 정확한 데이터를 유지할 수 있을 것이다. 객체지향언어가 아닌 언어에서는 이러한 추가적인 조건들을 반영하기가 어렵다. 그러나 객체지향언어에서는 제어자와 메서드를 이용해서 이러한 조건들을 코드에 쉽게 반영할 수 있다. 
아직 제어자에 대해서 배우지는 않았지만 위의 조건들을 반영하여 Time클래스를 작성해 보았다. 가볍게 참고만 하기 바란다. 


public class Time { 
      private int hour; 
      private int minute; 
      private int second; 

      public int getHour() { 
            return hour; 
      } 

      public void setHour(int h) { 
            if (h < 0 || h > 23) 
                  return; 
            hour=h; 
      } 

      public int getMinute() { 
            return minute; 
      } 

      public void setMinute(int m) { 
            if (m < 0 || m > 59) 
                  return; 
            minute=m; 
      } 

      public int getSecond() { 
            return second; 
      } 

      public void setSecond(int s) { 
            if (s < 0 || s > 59) 
                  return; 
            second=s; 
      } 



제어자를 이용해서 변수의 값을 직접 변경하지 못하도록 하고 대신 메서드를 통해서 값변경하도록 작성하였다. 값을 변경할 때 지정된 값의 유효성을 조건문으로 점검한 다음에 유효한 값일 경우에만 변경한다.
이 외에도 시간의 차를 구하는 함수와 같이 시간과 관련된 함수를 추가로 정의하여 Time클래스를 향상시켜 보는 것도 좋은 프로그래밍 공부거리가 될 것이다.

출처 -  http://cafe.naver.com/javachobostudy 


'Development > JavaEssential' 카테고리의 다른 글

연산자 1  (0) 2012.04.19
변수와 메서드  (0) 2012.04.18
패키지(package)  (0) 2012.02.07
인터페이스(Interface)  (0) 2012.01.24
추상클래스(Abstract class)  (0) 2012.01.24
Posted by linuxism
,

디자인 패턴은 소프트웨어 설계 시 특정 상황에서 자주 만나는 문제를 해결하기 위해 사용할 수 있는 재사용 가능한 솔루션을 말한다.

출처 - 토비의 스프링 3


컴퓨터 과학에서의 디자인 패턴

소프트웨어 개발 방법에서 사용되는 디자인 패턴은, 프로그램 개발에서 자주 나타나는 과제를 해결하기 위한 방법 중 하나로, 과거의 소프트웨어 개발 과정에서 발견된 설계의 노하우를 축적하여 이름을 붙여, 이후에 재이용하기 좋은 형태로 특정의 규약을 묶어서 정리한 것이다. 알고리즘과 같이 프로그램 코드로 바로 변환될 수 있는 형태는 아니지만, 특정한 상황에서 구조적인 문제를 해결하는 방식을 설명해 준다.

이 용어를 소프트웨어 개발 영역에서 구체적으로 처음 제시한 곳은, GoF(Gang of Four)라 불리는 네명의 컴퓨터 과학 연구자들이 쓴 서적 'Design Patterns: Elements of Reusable Object-Oriented Software'(재이용 가능한 객체지향 소프트웨어의 요소 - 디자인 패턴)이다. GoF는 컴퓨터 소프트웨어 공학 분야의 연구자인 에릭 감마리차드 헬름랄프 존슨존 블리시디스의 네명을 지칭한다.

[편집]디자인 패턴과 패턴 학회

GoF의 디자인 패턴과 그 멤버들 그리고 패턴에 관심을 갖는 학자, 엔지니어, 출판업자들이 모여서 PLoP라는 학회를 시작하게 된다. 1994년부터 시작된 학회는 2012년 현재까지 미국에서 각 주를 돌아가며, 전 세계의 패턴 저자 및 학습자들을 불러 새로운 패턴, 패턴언어, Agile등에 대해서 토의한다. 2010년도부터 AsianPLoP와 기타 Licensing된 미국밖 세계 PLoP움직임으로 퍼져나가고 있다. 한국에서도 KPLoP로 패턴저자인 손영수님과 그가 리딩하는 스터디 그룹인 EVA가 주축이 되어, 주요 국내 커뮤니티 행사등에서 패턴을 전도하고 있다.



팩토리 메서드 패턴(Factory method pattern)은 객체지향 디자인 패턴이다. 다른 생성 패턴들처럼, 이 패턴도 생성하려는 객체의 클래스를 정확히 지정하지 않으면서 객체를 만드는 문제를 다룬다. 팩토리 메서드 패턴은 이 문제를 객체를 만드는 또 다른 메서드를 정의하여 처리한다. 일반적으로, 팩토리 메서드라는 용어는 객체를 만드는 것이 주 목적인 메서드를 지칭하는데 주로 사용한다.

목차

  [숨기기

[편집]

[편집]C#

Pizza example:

public abstract class Pizza
{
    public abstract decimal GetPrice();
 
    public enum PizzaType
    {
        HamMushroom, Deluxe, Seafood
    }
    public static Pizza PizzaFactory(PizzaType pizzaType)
    {
        switch (pizzaType)
        {
            case PizzaType.HamMushroom:
                return new HamAndMushroomPizza();
 
            case PizzaType.Deluxe:
                return new DeluxePizza();
 
            case PizzaType.Seafood:
                return new SeafoodPizza();
 
        }
 
        throw new System.NotSupportedException("The pizza type " + pizzaType.ToString() + " is not recognized.");
    }
}
public class HamAndMushroomPizza : Pizza
{
    private decimal price = 8.5M;
    public override decimal GetPrice() { return price; }
}
 
public class DeluxePizza : Pizza
{
    private decimal price = 10.5M;
    public override decimal GetPrice() { return price; }
}
 
public class SeafoodPizza : Pizza
{
    private decimal price = 11.5M;
    public override decimal GetPrice() { return price; }
}
 
// Somewhere in the code
...
  Console.WriteLine( Pizza.PizzaFactory(Pizza.PizzaType.Seafood).GetPrice().ToString("C2") ); // $11.50
...

[편집]자바스크립트

Pizza example:

//Our pizzas
function HamAndMushroomPizza(){
  var price = 8.50;
  this.getPrice = function(){
    return price;
  }
}
 
function DeluxePizza(){
  var price = 10.50;
  this.getPrice = function(){
    return price;
  }
}
 
function SeafoodPizza(){
  var price = 11.50;
  this.getPrice = function(){
    return price;
  }
}
 
//Pizza Factory
function PizzaFactory(){
  this.createPizza = function(type){
     switch(type){
      case "Ham and Mushroom":
        return new HamAndMushroomPizza();
      case "DeluxePizza":
        return new DeluxePizza();
      case "Seafood Pizza":
        return new SeafoodPizza();
      default:
          return new DeluxePizza();
     }     
  }
}
 
//Usage
var pizzaPrice = new PizzaFactory().createPizza("Ham and Mushroom").getPrice();
alert(pizzaPrice);

[편집]루비

Pizza example:

class HamAndMushroomPizza
  def price
    8.50
  end
end
 
class DeluxePizza
  def price
    10.50
  end
end
 
class SeafoodPizza
  def price
    11.50
  end
end
 
class PizzaFactory
  def create_pizza(style='')
    case style
      when 'Ham and Mushroom'
        HamAndMushroomPizza.new
      when 'DeluxePizza'
        DeluxePizza.new
      when 'Seafood Pizza'
        SeafoodPizza.new
      else
        DeluxePizza.new
    end   
  end
end
 
# usage
factory = PizzaFactory.new
pizza = factory.create_pizza('Ham and Mushroom')
pizza.price #=> 8.5
# bonus formatting
formatted_price = sprintf("$%.2f", pizza.price) #=> "$8.50"
# one liner
sprintf("$%.2f", PizzaFactory.new.create_pizza('Ham and Mushroom').price) #=> "$8.50"


[편집]파이썬

# Our Pizzas
 
class Pizza:
    HAM_MUSHROOM_PIZZA_TYPE = 0
    DELUXE_PIZZA_TYPE = 1
    SEAFOOD_PIZZA_TYPE= 2
 
    def __init__(self):
        self.__price = None
 
    def getPrice(self):
        return self.__price
 
class HamAndMushroomPizza(Pizza):
    def __init__(self):
        self.__price = 8.50
 
class DeluxePizza(Pizza):
    def __init__(self):
        self.__price = 10.50
 
class SeafoodPizza(Pizza):
    def __init__(self):
        self.__price = 11.50
 
class PizzaFactory:
    def createPizza(self, pizzaType):
        if pizzaType == Pizza.HAM_MUSHROOM_PIZZA_TYPE:
            return HamAndMushroomPizza()
        elif pizzaType == Pizza.DELUXE_PIZZA_TYPE:
            return DeluxePizza()
        elif pizzaype == Pizza.SEAFOOD_PIZZA_TYPE:
            return SeafoodPizza()
        else:
            return DeluxePizza()
 
# Usage
pizzaPrice = PizzaFactory().createPizza(Pizza.HAM_MUSHROOM_PIZZA_TYPE).getPrice()
print "$%.02f" % pizzaPrice




Factory Method 패턴 (팩토리 메소드 패턴) [1] 은 GoF (Gang of Four; 4 명의 갱단들)에 의해 정의된 디자인 패턴 중 하나이다. Factory Method 패턴은 다른 클래스의 생성자를 서브 클래스에서 덮어쓸 수있는 자신의 메서드로 대체하여 응용 프로그램에 전문화된 객체의 생성을 서브 클래스로 내몰고, 클래스의 재사용성을 높이는 것을 목적으로한다.

Virtual Constructor 패턴이라고도 불리는 [1] .

목차

  [ 숨기기 ] 

클래스 다이어그램 편집 ]

Factory Method 패턴의 클래스 다이어그램 은 다음과 같다.

추상 클래스 Creator는 추상 클래스 Product를 생성하는 메소드를 가진다.  클래스 ConcreteCreator은 Creator의 구상 클래스이며, ConcreteProduct를 생성하는 메소드를 가진다.  ConcreteProduct는 Product의 구체적인 종류이다.

여기서 anOperation은 factoryMethod를 호출 Product 서브 클래스의 인스턴스를 얻고 이용한다. factoryMethod 같은 메소드는 factory method했다.

factoryMethod 기본 동작을 포함한 구체적인 방법이 될 수있다. 매개 변수를 그것에 의해 생성하는 클래스를 바꿀 수도있다. ConcreteCreator마다 작업 방법을 Product로 다른 클래스에 제공하는 케이스는 factoryMethod를 public으로 공개한다. [1] . 그러나 factoryMethod는 덮어 쓰지 가정이기 때문에 private로하지 않는다.

사용 예제 편집 ]

예를 들어, Java List의 요소를 다양한 정렬하는 프로그램을 생각한다. 이 소스 코드는 J2SE 1.5 이상 버전에서 작동한다.

import  java.util.ArrayList ; 
import  java.util.Arrays ; 
import  java.util.Collections ; 
import  java.util.Comparator ; 
import  java.util.List ;
 
/ / Creator에 해당하는 
abstract  class ListPrinter { 
    / / anOperaton에 해당하는 
    public  void printList ( List < String > list )  { 
        Comparator < String > comparator = createComparator ( ) ; 
        list =  New ArrayList < String > ( list ) ;
 
        Collections . sort ( list, comparator ) ;
 
        for  ( String Item : list )  { 
            System . out . println ( item ) ; 
        } 
    }
 
    / / factoryMethod에 해당하는 
    protected  abstract Comparator < String > createComparator ( ) ; 
}
 
/ / ConcreteCreator에 해당하는 
class DictionaryOrderListPrinter extends ListPrinter {
    @ Override
    protected Comparator < String > createComparator ( )  { 
        return  New DictionaryOrderComparator ( ) ; 
    } 
}
 
/ / java.util.Comparator가 Product에 해당하는
 
/ / ConcreteProduct에 해당하는 
class DictionaryOrderComparator Implements Comparator < String >  {
    @ Override
    public  int Compare ( String str1, String str2 )  { 
        return str1. compareTo ( str2 ) ; 
    } 
}
 
/ / ConcreteCreator에 해당하는 
class LengthOrderListPrinter extends ListPrinter {
    @ Override
    protected Comparator < String > createComparator ( )  { 
        return  New LengthOrderComparator ( ) ; 
    } 
}
 
/ / ConcreteProduct에 해당하는 
class LengthOrderComparator Implements Comparator < String >  { 
    public  int Compare ( String str1, String str2 )  { 
        return str1. length ( )  - str2. length ( ) ; 
    } 
}
 
/ / 기본 클래스 
public  class FactoryMethodSample { 
    public  static  void Main ( String args [ ] )  { 
        List < String > list =  Arrays . asList ( "딸기" , "모모" , "무화과" ) ;
 
        System . out . println ( "가나다 순으로보기 :" ) ; 
        New DictionaryOrderListPrinter ( ) . printList ( list ) ;
 
        System . out . println ( ) ;
 
        System . out . println ( "길이 순으로보기 :" ) ; 
        New LengthOrderListPrinter ( ) . printList ( list ) ; 
    } 
}

이 프로그램은 다음과 같은 결과를 출력한다.

가나다 순으로보기 :
딸기
무화과
모모

길이 정렬 :
모모
딸기
무화과

상반기에 목록을 사전 순으로 표시하여 나중에 목록을 문자열 길이 순으로 표시하고있다. 목록을 정렬 바꾸어보기 ListPrinter # printList 메서드는 정렬 바꾸어 사용 Comparator를 생성할 때 new 연산자를 사용하여 직접 생성하는 것이 아니라 추상 메서드 createComparator를 사용하여 서브 클래스 생성을 맡긴다.

관련된 패턴 편집 ]

factory method는 보통 template method ( Template Method 패턴 참조)이다 anOperation 호출된다. 그러나 factory method를 public으로 다른 클래스에서 부르는 경우도있다 [1] .

Abstract Factory 패턴 의 AbstractFactory 클래스는 factory method를 가지고 그것을 개별 서브 클래스가 재정 생성하는 Product를 바꾸는 수법이 일반적이다. 하지만 Prototype 패턴 을 사용하여 prototype과 객체의 변경에 의해 생성하는 Product를 바꾸는 방법도있다 [1] .

Abstract Factory 패턴의 차이 편집 ]

"객체 지향의 재사용을위한 디자인 패턴"에서는 Factory Method 패턴은 "클래스 패턴 '으로 분류되고있다. 반면 Abstract Factory 패턴은 "개체 패턴 '으로 분류되고있다.

Factory Method 패턴은 부모 클래스인 Creator 클래스가 자식 클래스이다 ConcreteCreator 클래스 객체의 생성을 맡긴다는, Creator 클래스와 ConcreteCreator 클래스와 관련이있다. 한편 Abstract Factory 패턴은 Client의 인스턴스가 ConcreteFactory의 인스턴스에 객체 생성을 맡긴다는 오브젝트 간의 관련이다.

관련 항목 편집 ]

참고 문헌 편집 ]

  1. e 에릭 감마 , 랄프 존슨 , 리처드 헬름 , 존 부리시디스 (의), 그라 디 · 부찌 (서문),本位田신이치, 요시다 카즈키 (監訳), "객체 지향의 재사용을 위해 디자인 패턴 ", 소프트 뱅크 퍼블리싱 , 1995. ISBN 978-4-7973-1112-9 .











'Framework & Platform > Common' 카테고리의 다른 글

모델1과 모델2의 차이점  (0) 2012.03.21
log4j.properties  (0) 2012.03.19
Refactoring  (0) 2012.03.18
Struts 2 따라잡기  (0) 2010.12.26
MVC(Model , View , Controller)  (0) 2010.11.28
Posted by linuxism
,

Refactory
리팩터리란 공장을 다각적으로 진단하여 전체적인 공장의 경쟁력 수준을 평가해 문제점을 제시하고 이에 대한 해결방안을 찾아 공장의 경쟁력 수준을 높이는 것이다. 구체적으로 공장의 발전 수준을 5단계로 구분하여 공장의 현재 상태를 진단하고 앞으로 공장이 나갈목표 단계를 설정, 계획적이고 체계적으로 공장을 혁신시키는 진단 프로그램이다. 평가항목은 공정개선, 품질경영, 작업개선, 사기 등 모두 10개로 이들 항목에 대한 정밀조사로 공장내 부문별 부조화를 제거하고 다음단계 목표에 나서게 된다. 

출처 - 네이버


소프트웨어 공학에서 리팩토링(refactoring)은 주로 '결과의 변경 없이 코드의 구조를 재조정함'을 뜻한다. 주로 가독성을 높이고 유지보수를 편하게 한다. 버그를 없애거나 새로운 기능을 추가하는 행위는 아니다. 사용자가 보는 외부 화면은 그대로 두면서 내부 논리나 구조를 바꾸고 개선하는 유지보수 행위이다.

마틴 파울러의 저서 《리팩토링》에 다양한 리팩토링 패턴들이 정리되어있다. 그 중 대표적인 것 몇 가지를 들자면, 필드 은닉메소드 추출타입 일반화메소드 이름 변경 등이 있다.

 리팩토링 (refactoring)은 컴퓨터 프로그래밍 에서 프로그램 외부에서 본 동작을 바꾸지 않고 소스 코드 의 내부 구조를 구성한다. 어떤 리팩토링 기법의 총칭으로서 사용된다. 충분히 확립된 기술은 말할 수 없으며, "리팩토링"단어에 정확한 정의가있는 것은 아니다.

목차

  [ 숨기기 ] 

리팩토링 등장 경위와 목적 편집 ]

리팩토링이 등장하기 전에는 일단 정상적인 작동을하는 프로그램 은 다시 닿으 안된다라고했다. 섣불리 손을 넣어 동작이 바뀌어 버리면, 이에 따라 관련 부분에 수정이 가해 곧 수정 프로젝트 전체에 파급 대처할 수 없게 될지도 모른다. 또한 소프트웨어 테스팅 을 충분히하고 정상적인 동작이 확인 되더라도 해당 프로그램을 조금이라도 변경하면 버그 (결함)이 발견되면 수정이 프로그램을 의심해야한다.

그러나 프로그램에는 반드시 변화가 있고 프로그램은 다만 누더기 투성이가되는 것은 불가피하다. 사양 개발 시작부터 확정되어있는 것은 적고, 개발을하고있는 동안에도 소프트웨어 에 대한 요구는 나날이 계속 변하고 있으며, 소프트웨어는 항상 사양 변경에 대응할 수있는 유연성이 요구된다. 또한 아무리 엄격하게 디자인해서 실제로 작동시키지 않으면 모르는 부분도 많고, 완벽한 설계를 실시하는 것은 불가능하다. 변경이 필요할 때 다시 손을 대지 못할 정도 복잡하게 된 소스 코드 를 수정하는 것은 곤란하고, 프로그래머 도 매우 용기가 요구되는 작업이다.

그래서 Smalltalk 프로그래머 등 사이에 평소부터 프로그램을 정리 사양 변경에도 대응할 수있는 정리 프로그램을 써 나갈 생각이 태어났다. 이 과정은 워드 커닝햄 , 켄트 벡 , 랄프 존슨 ( GoF 의 한 명) 등의 사람들이 큰 역할을했다. 이 기법을 리팩토링이라고있다. 또한 리팩토링은 프로그램의 전모를 파악하기 위해서도 효과적이다.버그를 발견했을 때도 소스 코드가 정리되고 있기 때문에 수정하다. 프로그래머로 평소 수정하는 코드에 다시 손을 넣는 것만 때문에 수정도 적극적으로 될 수있다. 또한 설계자는 설계 오류로 인한 아쉬움을 없앨 수있다. 디자인의 대체도된다고하는 의견도 사전 설계를 매우 단순화하는 역할도 가진다.

리팩토링은 객체 지향 디자인과 깊이 관련되어있다. 리팩토링의 대부분은 객체 지향의 성질에 따른 것이며, 객체 지향 코드 재사용 성을 극대화할 수있다. 객체 지향 프로그래밍을 할 수있는 언어라면 프로그래밍 언어 의 종류에 관계없이 리팩토링을 적용할 수있다.

리팩토링을 수행함으로써 개발이 정체되어 버리는 것은 아닌가하는 걱정을하는 경우도 많다. 리팩토링을 수행하는 동안 아무런 기능 추가도 행해지지 않는다. 그러나 대부분의 경우 디자인이 향상하는 것으로 기능 추가 및 버그 수정을하기 쉽고, 개발 속도는 안정뿐만 아니라, 빨리 될 수도있다. 또한 이미 작동하는 코드를 위태롭게한다 없다고하는 의견도 있지만, 절차를 준수 테스트를 많이 사용하면 어느 정도 위험을 줄일 수있다.

주요 리팩토링 편집 ]

메서드 추출
너무 메서드는 재사용성이 낮다. 메서드를 추출, 분할함으로써 재사용성이 높아지고, 호출 메소드의 내용도 읽기 쉽게된다. 처리 중복도 줄어든다.
양방향 연관을 단 방향으로 변경
불필요한 참조 관리를위한 수고를 늘리고 개체 의 삭제를 실패한다. 필요없는 연관 지운다.
클래스 추출
너무 자라 클래스를 분할한다. 클래스를 작게하는 것으로 그 클래스의 역할을 명확하게있다.
switch 문장 을 다형성 으로 교체
switch 문을 다형성로 대체하여 새로운 조건이 추가되어도 분기 부분은 변경할 필요가 없어진다.
멤버 이동
필드 및 메서드가 잘못된 클래스의 경우, 다른 클래스와 불필요한 관련이 늘어난다. 멤버를 이동하여 클래스의 책임을 구성합니다.
상속 을 위임 으로 대체
상속에서는 기본 클래스의 모든 멤버를 하위 클래스로 용서해야한다. 기본 클래스의 부분 기능을 이용하면 상속 대신 위임을 사용한다.
다운 캐스트 를 캡슐 화 한다
다운 캐스팅은 호환되지 않는 형식으로 변환시킬 수 있지만, 그것을 컴파일시 감지 할 수 없다. 일반 유형 ( 템플릿 )이없는 언어는 캡슐화하고 클라이언트 다운 캐스트의 수고를 줄일 수 있도록한다. 컬렉션 클래스 등으로 특히 필요합니다.
생성자를 Factory Method 로 대체
생성자는 해당 클래스의 개체를 반환할 수 밖에 없다. Factory Method의 소개로 유연한 인스턴스 화가 가능하게된다.
인수 개체의 도입
종종 함께 전달되는 여러 값을 개체로 정리한 것이 알기 쉽다.
클래스 메소드 속성의 이름을 변경하려면
클래스 이름과 메서드 이름과 속성 이름은 해당 클래 스나 메소드의 역할을 정확하게 설명합니다 할 필요가있다. 명칭이 잘못된 것이거나, 애매한 것이다 때는 명칭의 변경이 행해진다. 종종 처음에는 제대로였다 명칭도 다른 리팩토링 실행 후 적절한 분실될 수있다. 이 때는 계속 이름 변경 리팩토링을 수행하는 (⇒ 명명 규칙 (프로그래밍) ).

마틴 파울러 같은 사람이 쓴 리팩토링 해설서, "리팩토링 프로그래밍의 체질 개선 기술"(이하 "리팩토링")에서는 70여 가지의 리팩토링을들 수있다.

리팩토링을 할 타이밍 편집 ]

언제든지 뭐든지 리팩토링을하면된다는 것은 아니다. 납기가 빠듯한 다가온 경우에 리팩토링을하고있을 여유는없고, 리팩토링은 장래에 대비하여 실시하는 것으로 인해 그 리팩토링이 결실을 맺을 가능성은 적다. 또한 리팩토링이라고해도 역시 프로그래밍이기 때문에, 항상 오류를 위험은 지울 수 없다.

"리팩토링"에서는 기능을 추가하는 것과 리팩토링 때 명확하게 구별하는 것을 권장하고있다 (이 일을 비유하며 " 구현 모자를 리팩토링 모자 쓰고 다시 "이라한다). 리팩토링 만있어 개발은 진행하지 않으며, 어떤 리팩토링을해야할지 어느 정도 개발이 진행 않으면 모른다. 리팩토링을 시작하는 타이밍으로 코드 " 불길한 냄새 "를 느끼기 시작하면, 제안하고있다. 이것은 유사한 코드 중복과 너무 긴 메소드, 하나의 변경 때마다 여러 클래스가 영향을받는 등의 증상이 발견된 경우를 가리킨다. 또한 기능 추가 전 코드 검토 시 버그 수정 시에도 리팩토링을 권장하고있다.

테스트의 중요성 편집 ]

프로그램의 모양을 변경해야하기 때문에 리팩토링에 대해서는 테스트 가 매우 중요하다. 수정 단계적이고 조금씩하고 약간의 변경 때마다 테스트를 실시하는 것으로 동작의 이상을 재빨리 감지한다. 테스트없이 한 번에 리팩토링하면 프로그램의 동작이 어느새 바뀌어 버리고도 원인이 부위를 알 수 어려워진다. 프로그래머 테스트를 빼먹지하지 않기 때문에 간단하게 테스트를 수행할 수있는 도구 ( xUnit / JUnit 등)도 필요하다. 또한 테스트를 중요시하는 것은 민첩한 소프트웨어 개발 의 일부 개발 방법 ( 익스 트림 프로그래밍 등)의 " 테스트 우선 "나" 테스트 주도 개발 "의 개념 과도 일치한다.

리팩토링의 과제 편집 ]

리팩토링도 일부 문제가 존재한다. 예를 들어 데이터베이스 에서 변경하는 경우 데이터 마이 그 레이션을 할 필요가있다. 중간 계층을 사이에 두는 것으로 영향을 완화 수 있지만, 역시 시간이 걸리는 것은 부정할 수 없다. 또한 리팩토링은 종래와 같이 캡슐화된 클래스뿐만 아니라 인터페이스 도 변경할 수있다. 그것은 널리 공개된 인터페이 스인 경우 새 인터페이스와 이전 인터페이스를 모두 관리해야한다. 또한 수정하는 코드가 너무 심한 상태의 경우 새로 고쳐 쓴 것이 빠른 경우도있다. 아직 개발 기술을 위해 앞으로 여러 가지 문제가 발견될 가능성은있다.

통합 개발 환경의 리팩토링 기능 편집 ]

최근 통합 개발 환경 에는 리팩토링 기능이있는 것이 많다. 리팩토링은 수정되는 메서드 또는 클래스가 어떤 클래스에서 이용되고 있는지 조사할 필요가 발생한다. 이것을 단순한 텍스트 편집기 에서 알아보자하면 꽤 귀찮은 작업이 될 위, 간과을 가능성도 높다.

관련 항목 편집 ]

참고 문헌 편집 ]




'Framework & Platform > Common' 카테고리의 다른 글

모델1과 모델2의 차이점  (0) 2012.03.21
log4j.properties  (0) 2012.03.19
디자인 패턴  (0) 2012.03.18
Struts 2 따라잡기  (0) 2010.12.26
MVC(Model , View , Controller)  (0) 2010.11.28
Posted by linuxism
,