추상화

치로·2024년 7월 22일

1. 상속성과 다형성의 필요성

  • 상속성 : 개체 간의 공통적인 기능을 관리하기 위한 기법으로, 코드의 재사용을 통하여 유지 보수를 편리하게 함
  • 다형성(Override, Overload)은 서로 다른 기능이지만 메서드의 이름을 공통되게 처리함으로서 전체 프로그램의 일관성을 유지

2. Override 처리의 문제 발생 가능성

  • '@Override' 키워드를 사용하지 않고, 메서드를 재정의하는 과정에서 메서드 이름에 실수가 발생하더라도 에러가 아닌 새로운 메서드의 정의로 인식되므로,
    의도하지 않은 실행 결과를 가져올 수 있음
  • '@Override' 키워드를 사용하더라도 자식 클래스를 구현하는 개발자의 실수로 인하여 부모의 기능을 재정의하지 않았다면 다형성의 구현은 이루어지지 않게 됨

3. 상속 처리 시, @Override를 강제하기

  • 추상화 기법은 특정 클래스를 상속받은 경우, 부모의 특정 메서드를 무조건 재정의하도록 강제하는 기법
  • 특정 메서드를 재정의하도록 강제함으로써, 자식 클래스들을 작성하기 위한 가이드 역할을 할 수 있음
  • 즉, 추상화 기법은 java 클래스를 작성하기 위한 설계도를 소스 코드 형태로 제시하는 역할

4. 추상 메서드 만들기

  • 추상 메서드를 정의하기 위해서는 'abstract' 키워드를 사용하여 메서드를 정의
  • 추상 메서드는 자식 클래스가 구현해야하는 메서드의 가이드라인만 제시하기 위한 목적으로 사용되기 때문에, 선언만 가능하고 구현부가 없음
    // 선언만 가능하고, 구현부를 위한 블록이 존재하지 않음
    public abstract void sayHello() {...}

5. 추상 클래스

  • 추상 메서드를 포함한 클래스

  • 추상 메서드를 하나 이상 포함하고 있는 클래스는 반드시 '추상 클래스'로 정의되어야 함

  • 추상 클래스 'abstract' 키워드를 사용하여 정의
    //추상 클래스의 정의
    public abstract class Hello {
    public abstract void sayHello();
    }

  • 추상 클래스는 객체를 생성할 수 없고, 반드시 상속을 통해서 사용될 수 있다. 즉 추상 클래스는 다른 자식 클래스를 위한 '가이드라인'의 역할을 한다.

  • 공통 기능과 설계 제시를 모두 처라하기
    -> 추상 클래스는 생성자, 멤버변수, 일반 메서드 등을 포함
    -> 즉 공통 기능과 가이드 라인을 모두 정의하여 다른 클래스에게 상속됨
    public abstract class Hello {
    //멤버 변수
    private string msg;

    	// 생성자
    	public Hello(String msg) {this.msg = msg;}
    
    	//일반 메서드
    	public String getMsg() {..}
    	public void setMsg(String msg) {...}
    
    	// 추상 메서드
    	public abstract void sayHello();
    	}

예시 코드

package boxing;

public class Unit {
	private String name;

	public Unit(String name) {
		super();
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	public void attack () {
		System.out.println(this.name + " >> 공격 준비");
	}

}
package boxing;

public class Navy extends Unit{
	
	public Navy(String name) {
		super(name);
	}
	
	@Override
	public void attack () {
		super.attack();
		System.out.println(super.getName() + " >> 어뢰 발사!");
		System.out.println(super.getName() + " >> 지상 상륙");
	}
		
	public void nucleus() {
		System.out.println(super.getName() + " >> 탱크 공격!");
	}
}


package boxing;

public class Army extends Unit{

	public Army(String name) {
		super(name);
	}
	
	@Override
	public void attack () {
		super.attack();
		System.out.println(super.getName() + " >> 지상 공격 실행!");
	}
	
	public void tank() {
		System.out.println(super.getName() + " >> 탱크 공격!");
	}
}
package boxing;

public class AirForce extends Unit{
	
	public AirForce(String name) {
		super(name);
	}
	
	@Override
	public void attack () {
		super.attack();
		System.out.println(super.getName() + " >> 공중 공격 실행");
	}
	
	public void bombing() {
		System.out.println(super.getName() + " >> 폭격");
	}
}
package boxing;

public class Main01 {

	public static void main(String[] args) {
		//부대 지정
		Unit[] units = new Unit[5];
				
		units[0] = new AirForce("공군 1호");
		units[1] = new AirForce("공군 2호");
		units[2] = new Navy("해군 1호");
		units[3] = new Army("육군 1호");
		units[4] = new Army("육군 2호");

		//부대별 attack() 호출, for문
		// 부대 일괄 공격
		for(int i=0; i<units.length; i++) {
			units[i].attack();
		// 원래 클래스의 형태로 명시적 형변환 후 독립적으로 추가한 기능을 사용하는 코드 작성
		if(units[i] instanceof Army) {
			Army a = (Army)units[i];
			a.tank();
		} else if(units[i] instanceof Navy) {
			Navy n = (Navy)units[i];
			n.nucleus();
		} else {
			AirForce f = (AirForce)units[i];
			f.bombing();
		}
			
		}
	}

}

6. 추상 클래스 상속 받기

package abstractclass;

public abstract class Hello {
	private String msg;

	// 파라미터가 있는 생성자
	public Hello(String msg) {
		super();
		this.msg = msg;
	}

	// getter, setter 정의
	public String getMsg() {
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}
		
	// 선언만 되고 구현부를 위한 블록이 존재하지 않음
	// 추상 메서드
	public abstract void sayHello();
}
package abstractclass;
// 추상 클래스를 상속받는 과정을 일반 클래스의 상속과 동일하게 'extends' 키워드를 사용
public class korean extends Hello {

	// 부모 생성자 호출
	public korean(String msg) {
		super(msg);
	}
	
	// 부모 생성자의 호출을 처리하더라도 에러가 사라지지 않는 이유는, 부모 클래스가 정의하고 있는 추상 메서드를 Override를 하지 않았기 때문
	// 즉, 추상 메서드의 재정의를 요구하기 위하여 에러가 표시
	@Override
	public void sayHello() {
		
	}
}
package abstractclass;

public abstract class Unit {
	private String name;

	public Unit(String name) {
		super();
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	//추상 메서드
	public abstract void attack();
	public abstract void move();
}
package abstractclass;

public class Airforce extends Unit {

	public Airforce(String name) {
		super(name);
	}

	@Override
	public void attack() {
		System.out.println(this.getName() + ">> 공중 공격 실시");
	}

	@Override
	public void move() {
		System.out.println(this.getName() + ">> 비행기 이동 실시");
	}

}
package abstractclass;

public class Army extends Unit{

	public Army(String name) {
		super(name);
	}

	@Override
	public void attack() {
		System.out.println(this.getName() + ">> 육상 공격");
	}

	@Override
	public void move() {
		System.out.println(this.getName() + ">> 이동 준비");
	}

}
package abstractclass;

public class Navy extends Unit{

	public Navy(String name) {
		super(name);
	}

	@Override
	public void attack() {
		System.out.println(this.getName() + ">> 폭탄 발사");
	}

	@Override
	public void move() {
		System.out.println(this.getName() + ">> 잠수함 이동 실시");
	}

}
package abstractclass;

public class Main01 {

	public static void main(String[] args) {
		Army army = new Army("육군");
		Navy navy = new Navy("해군");
		Airforce air = new Airforce("공군");
		
		// 다형성이란, 객체의 이름이 서로 다르더라도 객체의 메서드를 호출할 때 고민하지 않기 위한 기법
		// 추상화는 다형성을 강제하는 것으로 객체를 사용하는 개발자의 편의 위한 클래스 작성 규칙
		army.attack();
		army.move();
		navy.attack();
		navy.move();
		air.attack();
		air.move();
	}

}

0개의 댓글