1. abstract 키워드

- 클래스와 메서드에 적용

- 추상 클래스는 실제 클래스들의 멤버변수와 메서드들의 이름을 통일할 목적으로 사용

- 추상 메서드가 있는 클래스는 반드시 추상 클래스여야 함

- 추상클래스에 반드시 추상 메서드만 선언할 필요는 없고 일반 메서드도 선언할 수 있음

 

- abstract 키워드를 사용하지 않았을 때 문제가 되는 예시

public class PopupStore {
	public void orderApple() {
		System.out.println("착즙 사과주스를 내줍니다.");
	}
	
	public void orderOrange() {
		System.out.println("착즙 오렌지주스를 내줍니다.");
	}
	
	public void orderGrape() {
		System.out.println("착즙 포도주스를 내줍니다.");
	}
}
public class Store extends PopupStore{
	
	@Override
	public void orderApple() {
		System.out.println("착즙 사과주스를 팝니다. 가격은 20000원");
	}
	
	@Override
	public void orderOrange() {
		System.out.println("착즙 오렌지주스를 팝니다. 가격은 24000원");
	}

	// 실수로 포도주스 가격 업데이트를 누락
}
public class MainClass {
	public static void main(String[] args) {
		// 2가지 문제점 체크
		// 1. 정식매장이 존재하는데 팝업스토어 생성 가능
		PopupStore ps = new PopupStore();
		
		// 2. 팝업스토어 클래스 내부에서 오버라이딩이 필수인 메서드가 누락될 수도 있음
		PopupStore s = new Store();
		s.orderApple();
		s.orderOrange();
		s.orderGrape();
	}
}

위 예시와 같이 abstract 키워드를 이용하지 않았을 때 위의 2가지 문제점이 발생할 수 있다.

포도주스를 오버라이딩 하지 않으면 경고를 띄우게 해야 하지 않을까? → 추상화 적용

PopupStore(부모타입)으로 Store(자식) 객체 형변환이 이루어짐

부모타입으로 선언한 객체에서도 자식이 오버라이딩했던 함수의 내용이 출력되는 것을 확인할 수 있다. (Promotion-자동형변환)

 

1) abstract class

- new 키워드를 이용하여 객체 생성 불가

- 오직 상속을 통해서 자식클래스로 구체화 시켜야 함

- new를 사용하여 직접 생성자를 호출할 수는 없지만 자식 객체가 생성될 때 super()를 호출하여 추상 클래스 객체를 생성하므로 추상 클래스도 생성자가 반드시 있어야 함

- 추상 메서드를 하나 이상 보유하고 있다면 해당 클래스는 추상 클래스 → 무조건 abstract 키워드를 붙여줘야 함

 

2) abstract method

- 추상 클래스 내에서만 선언 가능

- 추상 메서드는 메서드의 선언부만 있고, 메서드 실행 내용이 들어가는 중괄호 {}가 없는 메서드를 말함

- 추상 클래스 설계 시 자식 클래스가 반드시 실행 내용을 채우도록 강요하고 싶은 메서드가 있을 경우 해당 메서드를 추상 메서드로 선언

- 자식 클래스에서 반드시 부모 추상 클래스의 추상 메서드를 재정의하여 실행 내용을 작성해야 함

 

3) abstract 사용 예제

public abstract class PopupStore {
	// 1. 메서드에 abstract를 붙이면 해당 메서드는 추상메서드가 되고, 이 메서드는 반드시 오버라이딩 해야 함
	// 2. 추상메서드는 상속을 목적으로 선언한 메서드
	//    실행을 목적으로 선언된 메서드가 아니므로 메서드의 몸체({}) 부분이 없고 선언 마무리도 ;로 함
	// 3. 일반 클래스에는 추상 메서드 선언 불가
	//    추상메서드가 하나 이상 존재하면 무조건 추상클래스로 선언
	// 4. 추상클래스 내부에서는 추상메서드가 하나 이상 존재한다면 일반메서드 선언도 여전히 가능
	public abstract void orderApple();
	public abstract void orderOrange();
	public abstract void orderGrape();
	
	public void refund() {
		System.out.println("제품에 문제가 있어서 환불합니다.");
	}
}
public class Store extends PopupStore {
	@Override
	public void orderApple() {
		System.out.println("착즙 사과주스를 20000원에 팝니다.");
	}

	@Override
	public void orderOrange() {
		System.out.println("착즙 오렌지주스 24000원에 팝니다.");
	}

	@Override
	public void orderGrape() {
		System.out.println("가격은 못 정했습니다.");
	}
}
public class ConvenientStore extends PopupStore {
	@Override
	public void orderApple() {
		System.out.println("가당 사과주스 4000에 팝니다.");
	}

	@Override
	public void orderOrange() {
		System.out.println("가당 오렌지주스 5000에 팝니다.");
	}

	@Override
	public void orderGrape() {
		System.out.println("가당 포도주스 3500에 팝니다.");
	}
}
public class MainClass {

	public static void main(String[] args) {
		// PopupStore 클래스는 직접 객체 생성 불가능
		// PopupStore ps = new PopupStore();
		
		// PopupStore s = new Store();
		PopupStore s = new ConvenientStore();
		// 객체 종류에 따라 실행구문이 다르게 정의되었지만 명세는 같은 메서드
		s.orderApple();
		s.orderOrange();
		s.orderGrape();
		
		// 어떤 객체가 와도 공통적으로 실행되는 메서드
		s.refund();
	}
}

 

 

※ 템플릿 메서드 패턴 활용

public abstract class Lottery {
	// 템플릿 메서드 패턴은 큰 틀에서 호출구문은 구현메서드(실행문이 있는 메서드)로 정의해놓고
	// 구현메서드가 호출하는 추상메서드들은 상속 후에 특징을 정하도록 만들어서
	// 호출 순서는 그대로 가져갈 수 있도록 하되, 사용자가 특징만 정의하도록 하는 디자인 패턴
	
	// 구현메서드는 큰 틀은 같지만, 세부사항이 달라질 수 있는 내용을 먼저 작성
	public void lotteryCycle() {
		// 1. 어디서 사는가?
		buyLottery();
		// 2. 당첨 여부 확인
		checkWinLottery();
		// 3. 당첨 시 수령
		getLotteryMoney();
	}
	
	// 세부사항은 상속받은 주체가 무엇인지에 따라 다르게 정의할 수 있도록
	// 추상메서드만 정의해놓고, 추가적인 작업은 하지 않음
	abstract void buyLottery();
	abstract void checkWinLottery();
	abstract void getLotteryMoney();
}
public class KoreanLotto extends Lottery {
	@Override
	public void buyLottery() {
		System.out.println("한 게임에 천원짜리 로또를 삽니다.");
	}

	@Override
	public void checkWinLottery() {
		System.out.println("45C6의 확률을 뚫고 1등에 당첨되었습니다.");
	}

	@Override
	public void getLotteryMoney() {
		System.out.println("1등 상금으로 대략 수십억을 받았습니다.");
	}
}
public class StatesSuperball extends Lottery {
	@Override
	public void buyLottery() {
		System.out.println("미국 가서 슈퍼볼 복권을 삽니다.");
	}

	@Override
	public void checkWinLottery() {
		System.out.println("69C5 * 26C1 분의 1의 확률로 당첨되었습니다.");
	}

	@Override
	public void getLotteryMoney() {
		System.out.println("당첨 금액은 최소 수천억원입니다.");
	}
}
public class MainClass {
	public static void main(String[] args) {
		//Lottery lottery = new KoreanLotto();
		Lottery lottery = new StatesSuperball();
		lottery.lotteryCycle();
	}
}

'네트워크캠퍼스 > JAVA' 카테고리의 다른 글

예외처리  (0) 2024.01.17
인터페이스  (0) 2024.01.16
final  (0) 2024.01.15
싱글톤 패턴  (0) 2024.01.15
사용제한자  (0) 2024.01.12

+ Recent posts