객체지향이란 1편
1. 객체지향의 장점.
객체지향이라는 개념은 무엇보다 알기쉽고,만들기 쉽다는것입니다.
즉 어떠한 컴퓨터 프로그램을 만들때,현실세계에서 생각하는 것과 동일한 사고방식으로의 접근이 가능해졌다는 것이죠.
그래서 객체지향이라는 개념을 설명할때, 현실세계의 인용이 자연스럽게 나오는 것입니다.
또한 만들기 쉽다는건 그만큼 유지보수하는데에도 많은 비용을 요구하지 않는다는점 입니다.
2. 객체지향의 중요한 개념 3가지
1. 상속성 (inheritance)
객체지향을 말할때 상속성은 가장 중요한 요소들 중 한가지입니다. 상속성은 미리 만들어진
소스를 가지고 공유하며 재사용하고, 또한 특별한 부분에 대해서는 다시 재정의해서 사용하는
걸 말합니다. 즉, 개발하는데 있어서, 많은 부분을 생략할 수 있다는 거죠.또한, 어느부분에
오류가 있을때, 한부분의 수정만으로, 그 소스를 이용해 만든 모든 소스의 오류를 방지할
수 있다는 장점을 또한 가지고 있습니다.
2. 다형성(Polymophism)
뒤에서 다시 머리 터지게 설명 드리겠지만 맛뵈기로 간단하게나마 말씀드리자면 상속을 받은
것을 그대로 사용하지않고 입맛에 맞게 바꾸어줄수 있도록 하는것이 다형성입니다.
OVERRIDEN의 개념입니다. OVERRIDEN은 재사용성으로 통하기도 하는데 그말이 맞는 거
같습니다. 뒤에가면 OVERRIDEN 않쓰고는 SOURECE가 만들어 지지 않습니다. 특히 상속을
받은 경우는 더 하지요.
3. 캡슐화(Encapsulation)
캡슐화라고 하는것은 어떠한 데이타를 보호할 수 있다는 점입니다. 즉 어떠한 소스를 만들었을
때, 그 소스의 데이타를 보호할 수 있고, 보호 할 수 있다고 하는건 그 소스를 사용하는 입장에
서보면, 더욱더 안정된(또는 검증된) 소스를 사용한다는 것입니다. 같은 개념으로 data hiding
이라고 하는데 대부분의 번역서에선 데이타 은닉화라고합니다. 말이 좀 이상하죠? 이게 문제
입니다. 차라리 영어를 그대로 보는게 속편하죠(음.. 옆길로 셌군...)
객체지향의 중요한 개념3가지에 대해서 간략하게 나마 정리를 했습니다. 벌써 눈치들을 채셨겠지
만 저놈들은 따로따로 때어 놓고는 생각할 수가 없습니다. 상속이 이루어져야 다형성을 써먹을수
가 있고 상속성을 쓰기위해서는 데이타가 믿을 만해야 하는데 그걸 만들어 주는것은 캡슐화 입니
다. 그리고 완벽한 캡슐화를 이루기 위해서는 상속성과 다형성이 뒷받침이 되어야 함은 말할 필요
도 없지요. 예를 보면서 좀더 자세하게 이야기 해보겠습니다.(사실 캡술화가 젤루 만만해여^^;)
class Date
{
int day;
int monty;
int year;
}
지금 제가 아주 간단하게 Date라는 class를 만들어 보았는데, 이 클래스를 가만히 생각하게 되면
이런 점이 있을 수가 있겠죠. 지금 date라는 클래스는 날짜를 저장하기 위해서 만든건데 일단 day
라는 변수를 살펴보면 31보다 더 커다란 숫자가 저장되면 날짜를 잘못저장하게되는 거겠죠?
그러니깐
Date d = new Date();
하고 객체를 생성한 후 d.day = 40; 이라고 하게 되면 우리가 생각하는 개념상 잘못된 날짜가 만들
어 지겠죠? 이럴때 이런 변수들(외부에서 임의로 조작되었을때 원하지 않는결과가 나오는것들
또는 잘못된 결과가 나오는것들) 에대해서 외부로 부터 접근 제한을 시키는 것이 바로
encapsulation이라고 생각하시면 됩니다. 그래서 이런 캡슐화를 어떻게 구현하게 되냐면..
class Date
{
private int day;
private int month;
private int year;
}
라고 만드는 것이지요. 여기서 private는 접근제한자라 불리는 것인데. Date라는 클래스 외부에서의
접근을 막는 것입니다.즉
Date d = new Date;
한 후에 d.day = 40; 이라고 하면 에러가 나게 되는 것이죠.. 즉 외부로부터 어떠한 데이터를 보호
한다는 의미죠. 그런데 이렇게 보호만 한다고 해서 되는건 아니겠죠? 보호하는것까지는 좋은데
일단 만들어 놓은걸 사용하지 못하게 되는 것이니깐요. 그래서 이렇게 보호해놓은 데이타를 메소드
를 통해서 접근을 허락하는 것입니다.
class Date
{
private int day;
public void setDay(int targetDay)
{
day = targetDay;
}
}
제가 설명하기 쉽게 일단 변수를 하나로 줄였습니다. 자 그럼 설명을 계속하면 보시는 대로 day라
는 변수를 외부에서 접근하지 못하게 private로 선언한 다음 setDay라는 메소드를 제공해 주는것이
죠.그런데 위에 것만 보면 그전것과 크게 달라진 점이 없죠? 지금 나온 에제도 day라는 변수에 잘
못된 값이 들어갈 수 있을테니깐요. 그래서 메소드를 제공하긴 하는데 그냥 제공만 하는 것이
아니라.
class Date
{
private int day;
public void setDay(int targetDay)
{
if(day==targetDay)
else
{
// 이곳에는 잘못입력했으니깐 다시 입력하라는 식의 코딩이 들어가면 되겠죠.
}
}
}
이런식으로 만드는 겁니다. 그래서 다시 정리를 하자면 캡슐화라는것이 어려운 개념은 아닙니다.
일단 외부에서 조작이 되면 안되는 그런 변수에 대해서 private라고 선언한후 대신 메소드를 통해서
접근할 수 있도록 해주는 것이죠. 그리고 그 메소드에는 어떠한 검사부분이 들어가면 됩니다. 지금
넣으려는 값이 제대로 된것인지 아닌지를. 그래서 제대로 된것이라면 그냥 넣으면 되는 거구요. 제
대로가 아니라면 어떠한 처리부분이 들어가면 되겠죠?
1. Creating an Object
보통 자바에서 primitive data type(자바의 기본 데이타 타입을 선언하게 되면 실제적인 메모리에
할당되게 됩니다. 그렇지만 primitive data type이 아니라면(바로 reference type일 경우) 실제적인
메모리 공간에 할당되는게 아닙니다. 그런 레퍼런스 타입은 어떠한 주소값이 저장될 공간이 만들
어 지는 것이고, 실제로 다른곳에 실제적인 Object 가 저장이 되는것 이지요. 이런걸 보면 어느
정도 C에서 말하는 Pointer와 비슷합니다. 하지만 자바는 Pointer를 제공해 주지 않지요. 그져
reference라고 말하는것 뿐. 그리고 Pointer 연산은 안됩니다.(해도 되긴한데 엉망이 되어 버리죠)
그건 프로그램의 견고성 때문이지요. 뒤에서 자바의 특징을 말씀드릴때 다시한번 정리하겠지만
자바는 performance보다는 완벽한 객체지향을 목표로 만들어 졌으며 또한 서버에서 돌아가는 프로
그램 개발이 목적이였으므로 상당한 수준의 보안성과 안전성을 가지도록 만들어 졌습니다. Point를
써보신분들은 아시겠지만 이놈이 시스템을 아예 날려버리기도 하니까요 각설하고 객체를 만들때는
밑에서 처럼 new keyword를 사용 하시면 됩니다.
1) MyClass m = new MyClass();
Or
2) MyClass m;
m = new MyClass();
첫번째 예제는 선언과 동시에 Object를 하는 것이고, 두번째 예제는 선언과 Object생성을 나누어서
하게 되는것이죠. 두 예제의 다른점은 별반 없다고 생각하셔도 상관없습니다. 그리고 이렇게 만들
어진 Object에 접근을 하려면 dot 를 사용합니다. "variable dot member"의 형식입니다. 예를 들면
m.day 라는 식이죠. 바로 m이 어떤 객체를 가리키는 reference이구요, day가 그 객체가 가지고 있
는 member variable이 되는 거죠. 그럼 실제로 한번 예제를 해보도록 하죠. MyDate라는 class를
만들어 보도록 하겠습니다.
class MyDate
{
int day;
int month;
int year;
}
이렇게 만든 다음 javac로 compile하시면 되겠지요.
그다음 사용을 하시려면 객체를 만들어야 겠지요. 그래서 MyDate를 사용하는 class도 만들어
보겠습니다.
class TestMyDate
{
public static void main(String args[])
{
MyDate m = new MyDate();
m.day = 3;
m.month = 4;
m.year = 2000;
System.out.println("나의 생일은 " + m.year + "년 " + m.month + "월 " + m.day +"일 입니다.");
}
}
위의 TestMyDate를 실행시켜 보면 "나의 생일은 2000년 4월 3일 입니다." 라는 문장이 출력될 것입
니다. 소스를 설명드리면 3번째 줄에서 MyDate라는 class를 사용하기 위해 Object를 만들었습니
다. 그리고 4번째 줄에서 6번째 줄까지m.variable의 형식을 사용해 member variable에 값을 할당
하는 것이지요. 그리고 나서 7번째 줄에서 그런 값을 가져와서 출력하게 되는 것입니다. 이런
식으로 만들어진 Object의 값을 가져오고 할당할때는 referenceName.variable의 형식을 사용하면
되는 것입니다.
객체지향이란 2편
오늘은 객체지향 언어에서 사용하는 "is a" 관계에 대해 알아보도록 하죠. 일단 간단하게 말씀드리
면 상속관계 라고 할 수 있습니다. 상속관계에서의 상위계념은 하위개녀들을 포괄할 수 있는 내용
들이 들어갑니다. 예를 들어 포유류를 볼때 포유류는 젖먹이는 동물을 말합니다. 따라서 가장 상위
계념은 젖먹인다가 포함되는건 당연하겠죠. 포유류라는게 이런 동물들의 공통점을 뽑아 만든 개념
이니깐요. 즉 우리가 프로그래밍을 하다 보면 이런 관계를 가진 클래스들을 만들게 되는데.. 이런
관계에서 포유류를 상위클래스, 그리고 사슴, 사람 그리고 토끼 를 하위클래스로 보면 되는 것이
죠. 이럴때 우리는 이런 말을 사용합니다. 사슴은 포유류다. 또는 사람은 포유류다라는 말을. 즉 우
리가 다음과 같은 클래스를 만들게 되면
Employee
|
|
Manager
즉 코딩은 다음과 같겠죠.
class Employee
{
String name;
int salary;
int ssn;
}
class Manager extends Employee
{
String managerGroup;
// any coding...
}
이럴때 객체지향언어에서는 Manager is a Employee 라는 말을 사용합니다.위의 예와 같은 식이
죠.따라서 이런 "is a"관계가 바로 상속관계라고 생각하시면 됩니다.위에서 설명드리지 않은 것중에
extends라는 것이 있죠.이것이 바로 상속을 할때 사용하는 keyword입니다. 상위에 있는 클래스
(Employee를 말하죠.)의 모든것을 하위에 있는 클래스(Manager) 가 물려 받는 것이죠. 즉
Employee에 있는 Class에 있는 name, salary, ssn같은 것들을 Manager또한 사용하기 때문에
Manager를 새로 처음부터 만드는 것이 아니라 Employee를 상속받고 자신만의 변수(man
agerGroup)를 선언해서 사용하는 겁니다. 물론 재사용별骸?관련이 있겠구요. 자바에서는 단일
상속만을 지원합니다. 즉 모든클래스의 상위클래스는 반드시 하나만이 존재할 수 있다는 것입니다.
물론 그 상위클래스위의 상위클래스는 존재할 수 있겠죠. 바로 위가 하나라는 말입니다...물론 아시
죠? 또한 어제 했던 생성자와 연계시켜서생성자는 상속되질 않습니다. 당연하겠죠. 왜냐하면, 생
성자라고 하는 것이 하는일이 멤버 변수의 초기화를 하게 되는건데 상속을 받아서 새로운 멤버를
선언하게 될텐데. 그런건 자신의 클래스 안에서 해야되는거겠죠? 또한 생성자를 만드는 법이
return type이 없고,class의 이름과 같아야 하기 때문에 상속받아봐야 자신의 클래스에서는 생성자
의 역활을 할 수가 없겠죠?
객체지향이란 3편
객체의 다형성
객체지향의 진주이자 마지막 관문이며 가장많이 사용되며 가장많은 질문과 회의를 낳게하는 다형
성에 대해 적으며 간략한 객체지향에 대한 글을 접을까 합니다
1. 다형성(polymopism)
A. 정의
Super class type의 Reference변수로 sub class type의 객체를 참조한다. 쉽죠? ^^; 예를
봅시다.
예)
abstracte class Employee
{
String name;
float bs;
double salary;
abstracte public void setSalary();
//이렇게 하면 반드시 밑에서 overriden해야한다.
/* abstracte 선언은 밑에서 객체로 생성하지 못하게할 내용을 나타낼때 사용한다.
또한 abstracte클레스라고 해서 반드시 포함된 모든것이 다 abstracte가 되는건 아니다.
*/
}
class SalesEmployee extends Employee
{
public void setSalary()
{
salary = bs*1.5;
}
public void aa()
{
System.out.println("aa");
}
}
class RegularEmployee extends Employee
{
public void setSalary()
{
salary = bs*1.3;
}
public void bb()
{
System.out.println("bb");
}
}
일단은 예제 설명은 접어두고 예제의 내용은 기억하기 바란다.
자아 이제 심오한 이야기를 하겠다.
SalesEmployee s[] = new Employee[2];
이문장이 실행되면 결과는? 맞춘분께는 아무것도 못드림다. 결과는 에러. 그렇다면 아랫걸보자.
Employee e[] = new SalesEmployee[2];
이문장은 정상적으로 실행이된다. 왜? 소스코드를 보면 SalesEmployee가 기억장소에 저장되면은
name, bs, salary, setSalary(), 그리고 aa가 기억되어진다. 근데 위의 문장은 Employee type으
로 객체를 선언했다. 그러면 레퍼런스하는곳이 자신이 레퍼런스하고자 하는 숫자보다 작으므로
에러가 발생한다. 밑에 문장은 그런 이유로 가능한것이다.
기억하자. sub class type의 레퍼런스로 super class를 참조할 수 없다.
이제 다형성을 정의헤보자. 객체지향이 제사용성의 측면을 무쟈게 강조하고 있다는건 다 아실것
이다. 그럼 그런 연유에서 상속성이 나오게 된것도 알것이다. 그렇다면 변화를 주지 않고 사용
할 수 있는 것의 한계는 불보듯 뻔한것이다. 하나의 선언되어진 객체를 여러가지형태로 재정의
해서 사용할 수 있는 것이 다형성이다.
*overriden
재정의라고도 한다. 위의 소스를 보자 실제 메인부분에서(아직은 없지만) setSalary를 호출한다
면 무엇이 호출될까? 정답은 밑에서 정의한 것이 호출된다. 어떤 메쏘드를 호출할 때 상속이 이
루어졌다면 그 상속의 틀에있는 생성자들에 대하여 override검사라는것을 jvm이 한다. 그레서
맨 나중에 재정의 된것을 사용하게 되는것이다. 왜? 상상을 해보라. 기껏 재정의 해놓은게 늘쌍
부모클레스의 것만 사용된다면 허무하지 않겠는가? 위 소스를 완성해보자.
abstracte class Employee
{
String name;
float bs;
double salary;
abstracte public void setSalary();
}
class SalesEmployee extends Employee
{
public void setSalary()
{
salary = bs*1.5;
}
public void aa()
{
System.out.println("aa");
}
}
class RegularEmployee extends Employee
{
public void setSalary()
{
salary = bs*1.3;
}
public void bb()
{
System.out.println("bb");
}
}
public class PolyTest
{
public static void main(String args[])
{
Employee e[] = new Employee[2];
e[0] = new SalesEmployee;
e[0].bs=1000000;
e[0].setSalary();
e[1] = new RegularEmployee;
e[1].bs=1000000;
e[1].setSalary();
System.out.println(e[0].salary+":"+e[1].salary);
}
}
결과는? 직접해보시기를....
그리고 객체지향에 대해 궁금하신분은 아래 싸이트를 가보시기 바란다.
www.omtgroup.com