Java는 클래스를 중심으로 객체들을 설계하는 언어이다. 바꿔 말하면 문제를 해결하기 위해 클래스를 설계하고, 이를 인스턴스화 하여 사용한다.

또한 Java를 사용할 때 의 장점 중(객체지향 프로그래밍의 장점 중) 재사용성이 있는데, 이는 다음과 같이 해석할 수도 있다.

'비슷한 형태를 묶어 하나의 클래스를 만들고, 그 클래스로부터 각각의 문제를 해결한다.'

즉, 클래스의 구현과 사용을 분리하여 만드는 것이 일반적이다. 만약 현대자동차를 만드는 클래스 하나, 기아자동차를 만드는 클래스 하나와 같이 같은 형태의 문제를 각각의 클래스를 만들면 낭비이고 비효율을 초래한다.

여기까지 이해하면 다음과 같이 설계할 수 있다.

class Car{
	String company;
	String name;
	int speed;
    
	Car(String company; String name, int speed){
		this.company = company;
        this.name = name;
        this.speed = speed;
	}
    
	public void move(){
    	this.speed = 100;
		System.out.println(this.company + "의 " + this.name + "가 " + this.speed + "의 속도로 달립니다.");
	}
    
    public void stop(){
    	this.speed = 0;
        System.out.println(this.company + "의 " + this.name + "가 " + this.speed + "의 속도로 달립니다.");
    }
}

<이는 정말 간단한 예를 표현하기 위한것이니 왜 이렇게 짰는지는 묻지 말아주길 바란다.>

그런데, 위에서 말했듯이, 클래스의 구현과 사용은 분리하는것이 좋다. 위의 예는 클래스의 '사용'을 나타낸 것이다.

이를 어떻게 구현과 사용으로 분리할 수 있을까?


구현은 Abstract(추상화) 사용은 Extends(상속)

abstract의 사전적 의미는 추상이다. 추상의 국어사전 속 의미는

추상(抽象) [명사] [심리 ] 여러 가지 사물이나 개념에서 공통되는 특성이나 속성 따위를 추출하여 파악하는 작용.
<출처: 네이버 국어사전>

이를 프로그래밍 관점에서 보자면, "객체들에 대해 공통적인 속성을 추상화 시켜놓고 해당 속성을 각각의 Class에서 구현하고 사용한다."로 생각하면 된다.

자동차로 예를 들면, 쉽게 자동차는 굴러가고, 춘다. 그런데 각각의 자동차가 어떤 속도로 굴러갈지, 어떻게 멈출지는 모르는 법이다. 따라서 위에서 만들었던 Car class에서 movestop을 추상화하면 된다.

Java에서 추상화 하는 방식은 abstract한정자를 사용하면 된다. 또한 abstract한정자를 갖는 클래스는 abstract class, 즉 추상 클래스가 된다.

우리는 각각의 자동차가 어떻게 굴러가는지, 또 어떻게 멈추는지 모른다. 즉 추상화하고자 하는 method의 동작 방식을 전혀 모른다. 따라서 abstract method는 본문 내용을 가져서는 안된다. 즉, 다음과 같이 표현하여야 한다

abstract public void move(); (단, 우리는 동작방식이 어떻게 될지 모르는거지, 인자로 뭐가 들어올지는 설정할 수 있다. 가령, 움직이는 속도를 전달받는다 하면 abstract public void move(int speed);와 같이 나타내면 된다.)


그러면 실제로는 어떻게 해야할까?

앞선 내용을 바탕으로 구현과 사용을 분리해 보면, 다음과 같이 나타낼 수 있다.

public abstract class CarFrame{
    int speed;
    String name;
    String company;
    
    abstract public void move();
    abstract public void stop();
    
    public void Status(){
    	System.out.println(this.company + "의 " + this.name + " 현재 속도: " + this.speed);
    }
    
    public int getSpeed() {	return this.speed;	}
    public String getName() {	return this.name;	}
    public String getCompany() {	return this.company;	}
    
    public void setSpeed(int speed) {	this.speed = speed;	}
    public void setName(String name) {	this.name = name;	}
    public void setCompany(String company) {	this.company = company;	}
}

public class Car extends CarFrame{
    public Car(String name, String company){
    	setSpeed(0);
    	setName(name);
    	setCompany(company);
    }
    
    public void move(){	setSpeed(100);	}
    public void stop(){	setSpeed(0);    }
}

public class mainAbstract {
	public static void main(String[] args) {
		Car Sportage = new Car("스포티지", "기아자동차");
		Car Tucson = new Car("투싼", "현대자동차");
		Sportage.Status();
		Tucson.Status();
		/*****************************/
		Sportage.move();
		Tucson.move();
		Sportage.Status();
		Tucson.Status();
		/*****************************/
		Sportage.stop();
		Tucson.stop();
		Sportage.Status();
		Tucson.Status();
	}
}

CarFarme이라는 abstract class, 추상 클래스를 통해 자동차들에 대해 하나로 구현하였고, 각각의 자동차에 대해 Car라는 class를 인스턴스화 함으로써 사용하게 하였다. (이때 getter와 setter를 사용하지 않고 직접 변수 getter setter를 사용하고 싶으면 CarFrame의 변수들에 대해 접근제한자를 바꿔주면 된다.)

아래의 maniAbstract 클래스를 실행하면 다음과 같은 결과가 나온다.

move 이후에 속도가 100이 찍힌다.


앞에서 우리가 사용할 때 공통적인 내용을 추상화 했다. 프로그래밍을 시작한지 얼마 안된 사람이라면 다음과 같은 의문을 가질 수 있다.

"어? 그러면 쉐보레와 현대/기아가 있을때, 현대/기아만 갖는 속성은 어떻게 나타낼 수 있어요?"

우리는 현대 자동차와 기아 자동차가 같은 내용을 가진다고 가정 했다. (같은 그룹이라서..)

이는 우리가 Car를 상속받아 현대자동차 클래스 / 쉐보레 클래스를 각각 구현하여, 해당하는 클래스에 멤버변수나 메소드를 추가해주면 된다.

그러한 예를 나타내고 상속클래스 게시글을 마치겠다.


전방충돌감지 레이더를 장착한 기아 자동차의 스포티지와 깡통 옵션으로 출고된 트래버스를 구현할 때, 다음처럼 구현할 수 있다.

쉐보레를 싫어하는게 아니라 구현의 귀찮음으로 인해 스포티지만 전방인식 레이더가 있다고 구현했습니다.

public class Kia extends Car{
	int frontObject = -1;
	public Kia(String name, String company) {	super(name, company);	this.frontObject = -1;}
	
	public void frontObject(int distance) {
		this.frontObject = distance; 
	}
	
	@Override
	public void move() {
		if(frontObject > 0) {
			super.setSpeed(100 - frontObject);
		}else {
			super.setSpeed(100);
		}
		
		if(super.getSpeed() < 30) {
			System.out.println("전방 충돌 주의!!! 긴급제동을 시작합니다.");
			super.setSpeed(0);
		}
	}
}

public class Chevrolet extends Car{
	public Chevrolet(String name, String company) {	super(name, company);	}
}

public class mainAbstract {
	public static void main(String[] args) {
		System.out.println("=====짧은머리 개발자=====");
		Kia Sportage = new Kia("스포티지", "기아자동차");
		Chevrolet Traverse = new Chevrolet("트래버스", "쉐보레");
		
		Sportage.move();
		Traverse.move();
		Sportage.Status();
		Traverse.Status();
		
		System.out.println("===50m 전방 사람===");
		Sportage.frontObject(50);
		Sportage.move();
		Sportage.Status();
		System.out.println("===30m 전방 사람===");
		Sportage.frontObject(70);
		Sportage.move();
		Sportage.Status();
		System.out.println("===20m 전방 사람===");
		Sportage.frontObject(80);
		Sportage.move();
		Sportage.Status();
	}
}

Chevrolet Class는 frontObject라는게 없기 때문에 Traverse.frontObject를 사용할 수 없어서 Sportage에만 사용하였습니다.

+ Recent posts