[Java] 클래스간의 관계- 포함관계
상속이외에도 클래스를 재사용하는 또 다른 방법이 있는데, 그것은 클래스간에 포함관계를 맺어
주는 것이다. 클래스 간의 포함관계를 맺어 주는 것은 한 클래스의 멤버변수로 다른 클래스 타입의 참조 변수를 선언하는 것을 뜻한다.
♠ 원을 표현하기 위한 Circle이라는 클래스를 작성
class Circle{
int x; //원점의 x 좌표
int y; //원점의 y 좌표
int r; // 반지름
}
// 좌표상의 한 점을 다루기 위한 Point 클래스
class Point{
int x; //x좌표
int y; //y좌표
}
//Point 클래스를 재사용해서 Circle 클래스를 작성한다면 다음과 같이 할 수 있다.
class Circle{
int x;
int y;
int r;
}
class Circle{
Point c = new Point(); //원점
int r;
}
하나의 거대한 클래스를 작성하는 것보다 단위별로 여러 개의 클래스를 작성한 다음, 이 단위 클래스들을 포함관계로
재사용하면 보다 간결하고 손쉽게 클래스를 작성할 수 있다.
클래스간의 관계 결정하기
클래스를 작성하는데 있어서 상속관계를 맺어 줄 것인지 포함관계를 맺어 줄 것인지를 결정하는 것은 떄떄로 혼돈스러울 수있다.
위에서 예를 든 Circle 클래스의 경우, Point클래스를 포함시키는 대신 상속관계를 맺어 주었다면 다음과 같다.
class Circle P
point c = new Point();
int r;
}
class Circle extends Point{
int r;
}
원 은 점이다. - Circle is a Point 원 은 점을 가지고 있다 - Circle has a Point |
클래스를 가지고 문장을 만들었을 떄 '~은 ~이다'라는 문장이 성립한다면, 서로 상속관계를 맺어주고,'~은 ~을 가지고 있다.'는 문장이 성립한다면 포함관계를 맺어주면 된다.
Circle클래스와 Point 클래스간의 관계는 상속관계보다 포함관계를 맺어주는것이 더 옳다.
상속관계 '~은 ~이다.(is-a)'
포함관계 '~은 ~을 가지고 있다.(has-a)'
public class DrawShape {
public static void main(String[] args) {
Point[] p = { new Point(100, 100),
new Point(140, 50),
new Point(200, 100)
};
Triangle t = new Triangle(p);
Circle c = new Circle(new Point(150,150),50);
t.draw(); //삼각형을 그린다.
c.draw(); //원을 그린다.
}
}
class Shape{
String color = "black";
void draw() {
System.out.printf("[color=%s]%n", color);
}
}
class Point{
int x;
int y;
Point(int x, int y){
this.x = x;
this.y = y;
}
Point(){
this(0, 0);
}
String getXY() {
return "("+x+","+y+")"; //x와 y의 값을 문자열로 반환
}
}
class Circle extends Shape{
Point center; //원의 원점좌표
int r; //반지름
Circle() {
this(new Point(0,0),100); //Circle(Point center,int r)를 호출
}
Circle(Point center, int r){
this.center = center;
this.r = r;
}
void draw() { //원을 그리는 대신에 원의 정보를 출력하도록 했다.
System.out.printf("[center=(%d,%d),r=%d, color=%s]%n",
center.x, center.y, r, color);
}
}
class Triangle extends Shape{
Point[] p =new Point[3];
Triangle(Point[] p) {
this.p = p;
}
void draw() {
System.out.printf("[p1=%s, p2=%s,p3=%s, color=%s]%n",
p[0].getXY(), p[1].getXY(), p[2].getXY(),color);
}
}
[p1=(100,100), p2=(140,50),p3=(200,100), color=black]
[center=(150,150),r=50, color=black]
public class DeckTest {
public static void main(String[] args) {
Deck d = new Deck(); // 카드 한벌을 만든다.
Card c = d.pick(0); //섞기 전에 제일 위의 카드를 뽑는다.
System.out.println(c); //System.out.println(c.toString());과 같다.
d.shuffle(); // 카드를 섞는다.
c = d.pick(0); //섞은 후에 제일 위의 카드를 뽑는다.
System.out.println(c);
}
}
class Deck{
final int CARD_NUM = 52;
Card cardArr[] = new Card[CARD_NUM];//Card 객체 배열을 포함
Deck() { //Deck카드를 초기화한다.
int i =0;
for(int k=Card.KIND_MAX; k > 0; k--)
for(int n=0; n < Card.NUM_MAX; n++)
cardArr[i++] =new Card(k,n+1);
}
Card pick(int index) { //지정된 위치(index)에 있는 카드 하나를 꺼내서 반환
return cardArr[index];
}
Card pick() { //Deck에서 카드 하나를 선택한다.
int index = (int)(Math.random() * CARD_NUM);
return pick(index);
}
void shuffle() {
for(int i=0; i < cardArr.length; i++) {
int r = (int)(Math.random() * CARD_NUM);
Card temp = cardArr[i];
cardArr[i] = cardArr[r];
cardArr[r] = temp;
}
}
} // Deck 클래스 끝
class Card{
static final int KIND_MAX = 4; // 카드무늬 수
static final int NUM_MAX = 13; //무늬별 카드수
static final int SPADE = 4;
static final int DIAMOND = 3;
static final int HEART = 2;
static final int CLOVER = 1;
int kind;
int number;
Card(){
this(SPADE,1);
}
Card(int kind, int number){
this.kind = kind;
this.number =number;
}
public String toString() {
String[] kinds = {"", "CLOVER","HEART","DIAMOND","SPADE"};
String numbers = "0123456789XJQK"; // 숫자 10은 X로 표현
return "kind : " + kinds[this.kind]
+", number : " + numbers.charAt(this.number);
}
}
단일 상속
다른 객체지향 언어인 C++에서는 여러 조상 클래스로부터 상속받는 것이 가능한 '다중상속'을 허용하지만 자바에서는 오직 단일 상속만을 허용한다. 그래서 둘 이상의 클래스로 부터 상속을 받을 수 없다.
다중상속에 비해 클래스 간의 관계가 보다 명확해지고 코드를 더욱 신뢰할 수 있게 만들어 준다는 점에서 이점을 가지는 단일상속이다.
package ch07;
class TV{
boolean power;
int channel;
void power() {power = !power;}
void channelUp() {++channel;}
void channelDown() {--channel;}
}
class VCR{
boolean power;
int counter = 0;
void power() { power =!power;}
void play() {/*내용생략*/}
void stop() {/*내용생략*/}
void rew() {/*내용생략*/}
void ff() {/*내용생략*/}
}
public class TVCR extends Tv {
VCR vcr = new VCR();
void play() {
vcr.play();
}
void stop() {
vcr.stop();
}
void rew() {
vcr.rew();
}
void ff() {
vcr.ff();
}
}
Object 클래스 - 모든 클래스의 조상
object 클래스는 모든 클래스 상속계층도의 최상위에 있는 조상클래스이다. 다른 클래스로 부터 상속 받지 않는 모든 클래스들은 자동적으로 Object 클래스로부터 상속받게 함으로 이것을 가능하게 한다.