Java 사전학습_6
<Java 사전학습_6>
- 추상 클래스 활용하기(26강)
- 추상 클래스와 템플릿 메서드 활용(27강)
- 인터페이스 선언과 구현하기(28강)
- 인터페이스와 다형성 구현(29강)
- 인터페이스 활용하기(30강)
1. 추상클래스 활용하기(26강)
추상 클래스(abstract class)
추상 메서드를 포함한 클래스
추상 메서드는 구현코드 없이 메서드의 선언만 있음
abstract 예약어 사용
추상 클래스는 new(인스턴스화)할 수 없음
abstract int add(int x, int y); //선언만 있는 추상메서드
int add(int x, int y) {} //{}부분이 구현내용. 추상메서드 아님
package abstractex;
public abstract class Computer { //추상클래스
public abstract void display(); //구현코드 {} 없음, 추상메서드
public abstract void typing();
public void turnOn() {
System.out.println("전원을 켭니다");
}
public void turnOff() {
System.out.println("전원을 끕니다");
}
}
package abstractex;
public class DeskTop extends Computer{ //전부 구현화하면 abstract 안써도됨
@Override
public void display() {
System.out.println("DeskTop display()");
}
@Override
public void typing() {
System.out.println("Desktop typing()");
}
}
package abstractex;
public abstract class LabTop extends Computer{
@Override
public void display() {
System.out.println("LabTop display()");
}
}
package abstractex;
public class MyNote extends LabTop{
@Override
public void typing() {
System.out.println("MyNote typing()");
}
}
package abstractex;
public class ComputerTest {
public static void main(String[] args) {
// Computer c1 = new Computer(); //추상클래스는 new(인스턴스화)할 수 없음
Computer c2 = new DeskTop();
// Computer c3 = new LabTop();
Computer c4 = new MyNote();
c2.display(); //DeskTop display()
c4.display(); //LabTop display()
}
}
2. 추상클래스와 템플릿 메서드 활용(27강)
템플릿 메서드
추상 메서드나 구현된 메서드를 활용하여 전체 기능의 흐름(시나리오)을 정의하는 메서드
final로 선언하면 하위 클래스에서 재정의할 수 없음
추상 클래스와 템플릿 메서드
프레임워크에서 많이 사용되는 설계 패턴
추상 클래스로 선언된 상위 클래스에 메서드를 활용하며 전체적인 흐름을 정의하고 하위 클래스에서 다르게 구현되어야 하는 부분은 추상 메서드로 선언해서 하위 클래스가 구현하도록 함
package template;
public abstract class Car {
public abstract void drive();
public abstract void stop();
public abstract void wiper();
public void washCar() {}; //구현코드 안넣고 각 하위클래스에서 재정의
public void startCar() {
System.out.println("시동을 켭니다.");
}
public void turnOffCar() {
System.out.println("시동을 끕니다.");
}
public final void run() { //final 재정의 불가, 템플릿메서드
startCar();
drive();
wiper();
stop();
washCar();
turnOffCar();
}
}
package template;
public class ManualCar extends Car{
@Override
public void drive() {
System.out.println("사람이 운전합니다.");
System.out.println("사람이 핸들을 조작합니다.");
}
@Override
public void stop() {
System.out.println("사람이 브레이크로 정지합니다.");
}
@Override
public void wiper() {
System.out.println("사람이 수동으로 와이퍼를 작동합니다.");
}
}
package template;
public class AiCar extends Car{
@Override
public void drive() {
System.out.println("자율 주행합니다.");
System.out.println("자동차가 스스로 방향을 전환합니다.");
}
@Override
public void stop() {
System.out.println("자동차가 스스로 멈춥니다.");
}
@Override
public void wiper() {
System.out.println("자동차가 스스로 와이퍼를 작동합니다.");
}
@Override
public void washCar() {
System.out.println("자동으로 세차가 됩니다.");
}
}
package template;
public class CarTest {
public static void main(String[] args) {
Car myCar = new ManualCar();
myCar.run();
System.out.println("==========");
Car yourCar = new AiCar();
yourCar.run();
}
}
final 예약어
final 변수는 값이 변경될 수 없는 상수
public static final double PI = 3.14;
final변수는 오직 한 번만 값을 할당할 수 있음
final메서드는 하위 클래스에서 재정의(overriding)할 수 없음
final클래스는 더 이상 상속되지 않음
템플릿 메서드 구현 예
각 PlayerLevel별 가능한 기능은 다름
단, 기능의 순서는 run(), jump(), turn()의 순서
기능의 순서와 반복에 대한 구현은 go(int) 메서드에서 구현(템플릿 메서드)
package gamelevel;
public abstract class PlayerLevel {
public abstract void run();
public abstract void jump();
public abstract void turn();
public abstract void showLevelMessage();
final public void go(int count) {
run();
for(int i = 0; i < count; i++) {
jump();
}
turn();
}
}
package gamelevel;
public class Player {
private PlayerLevel level;
public Player() {
level = new BeginnerLevel();
level.showLevelMessage();
}
public PlayerLevel getLevel() {
return level;
}
public void upgradeLevel(PlayerLevel level) {
this.level = level;
level.showLevelMessage();
}
public void play(int count) {
level.go(count);
}
}
package gamelevel;
public class BeginnerLevel extends PlayerLevel {
@Override
public void run() {
System.out.println("천천히 달립니다.");
}
@Override
public void jump() {
System.out.println("뛸 수 없습니다.");
}
@Override
public void turn() {
System.out.println("전환할 수 없습니다.");
}
@Override
public void showLevelMessage() {
System.out.println("===초보자 레벨입니다===");
}
}
package gamelevel;
public class AdvancedLevel extends PlayerLevel{
@Override
public void run() {
System.out.println("빠르게 달립니다.");
}
@Override
public void jump() {
System.out.println("높이 뜁니다.");
}
@Override
public void turn() {
System.out.println("전환할 수 없습니다.");
}
@Override
public void showLevelMessage() {
System.out.println("===중급자 레벨입니다.===");
}
}
package gamelevel;
public class SuperLevel extends PlayerLevel{
@Override
public void run() {
System.out.println("최고로 빠르게 달립니다.");
}
@Override
public void jump() {
System.out.println("최고로 높이 뜁니다.");
}
@Override
public void turn() {
System.out.println("한 바퀴 돕니다.");
}
@Override
public void showLevelMessage() {
System.out.println("===고급 레벨입니다===");
}
}
package gamelevel;
public class MainBoard {
public static void main(String[] args) {
Player player = new Player();
player.play(1);
AdvancedLevel levelA = new AdvancedLevel();
player.upgradeLevel(levelA);
player.play(2);
SuperLevel levelS = new SuperLevel();
player.upgradeLevel(levelS);
player.play(3);
}
}
3. 인터페이스 선언과 구현하기(28강)
인터페이스(interface)
모든 메서드가 추상 메서드(abstract method)로 이루어진 클래스
형식적인 선언만 있고 구현은 없음
인터페이스에 선언된 모든 메서드는 public abstract로 추상메서드
인터페이스에 선언된 모든 변수는 public static final로 상수
package interfaceex;
public interface Calc {
double PI = 3.14;
int ERROR = -999999999;
int add(int num1, int num2);
int substract(int num1, int num2);
int times(int num1, int num2);
int divide(int num1, int num2);
}
package interfaceex;
public abstract class Calculator implements Calc{
@Override
public int add(int num1, int num2) {
return num1 + num2;
}
@Override
public int substract(int num1, int num2) {
return num1 - num2;
}
}
package interfaceex;
public class CompleteCalc extends Calculator{
@Override
public int times(int num1, int num2) {
return num1 * num2;
}
@Override
public int divide(int num1, int num2) {
if(num2 != 0) {
return num1 / num2;
}
return ERROR;
}
public void shoeInfo() {
System.out.println("Calc 인터페이스를 구현하였습니다.");
}
}
package interfaceex;
public class CalculatorTest {
public static void main(String[] args) {
int num1 = 10;
int num2 = 2;
Calc calc = new CompleteCalc();
System.out.println(calc.add(num1, num2));
}
}
인터페이스 구현과 형 변환
인터페이스를 구현한 클래스는 인터페이스형으로 선언한 변수로 형 변환할 수 있음
상속에서의 형 변환과 동일한 의미
단 클래스 상속과 달리 구현 코드가 없기 때문에 여러 인터페이스를 구현할 수 있음
형 변환 시 사용할 수 있는 메서드는 인터페이스에 선언된 메서드만 사용할 수 있음
4. 인터페이스와 다형성 구현(29강)
인터페이스와 다형성
인터페이스는 “Client Code”와 서비스를 제공하는 “객체”사이의 약속이다
어떤 객체가 어떤 interface타입이라 함은 그 interface가 제공하는 메서드를 구현했다는 의미
Client는 어떻게 구현되었는지 상관없이 interface의 정의만을 보고 사용할 수 있음 (ex. JDBC)
다양한 구현이 필요한 인터페이스를 설계하는 일은 매우 중요한 일
package scheduler;
public interface Scheduler {
void getNextCall();
void sendCallToAgent();
}
package scheduler;
public class RoundRobin implements Scheduler{
@Override
public void getNextCall() {
System.out.println("상담 전화를 순서대로 대기열에서 가져옵니다.");
}
@Override
public void sendCallToAgent() {
System.out.println("다음 순서 상담원에게 할당합니다.");
}
}
package scheduler;
public class LeastJob implements Scheduler{
@Override
public void getNextCall() {
System.out.println("상담 전화를 순서대로 대기열에서 가져옵니다.");
}
@Override
public void sendCallToAgent() {
System.out.println("대기가 가장 적은 상담원에게 할당합니다.");
}
}
package scheduler;
public class PriorityAllocation implements Scheduler{
@Override
public void getNextCall() {
System.out.println("등급이 높은 고객의 전화를 먼저 가져옵니다.");
}
@Override
public void sendCallToAgent() {
System.out.println("업무 스킬이 가장 높은 상담원에게 우선 할당합니다.");
}
}
package scheduler;
import java.io.IOException;
public class SchedulerTest {
public static void main(String[] args) throws IOException {
System.out.println("전화 상담 배분방식을 선택하세요. R, L, P");
int ch = System.in.read();
Scheduler scheduler = null;
if(ch == 'R' || ch == 'r') {
scheduler = new RoundRobin();
}
else if(ch == 'L' || ch == 'l') {
scheduler = new LeastJob();
}
else if(ch == 'P' || ch == 'p') {
scheduler = new PriorityAllocation();
}
else {
System.out.println("지원하지 않는 기능입니다.");
return;
}
scheduler.getNextCall();
scheduler.sendCallToAgent();
}
}
인터페이스의 요소
상수
모든 변수는 상수로 변환됨
추상 메서드
모든 메서드는 추상메서드
디폴트 메서드
기본 구현을 가지는 메서드, 구현 클래스에서 재정의할 수 있음
정적 메서드
인스턴스 생성과 상관없이 인터페이스 타입으로 사용할 수 있는 메서드
private 메서드
인터페이스를 구현한 클래스에서 사용하거나 재정의할 수 없음. 인터페이스 내부에서만 기능을 제공하기 위해 구현되는 메서드
5. 인터페이스 활용하기(30강)
package interfaceex;
public interface Buy {
void buy();
default void order() {
System.out.println("구매주문");
}
}
package interfaceex;
public interface Sell {
void sell();
default void order() {
System.out.println("판매주문");
}
}
package interfaceex;
public class Customer implements Buy, Sell{
@Override
public void sell() {
System.out.println("판매하기");
}
@Override
public void buy() {
System.out.println("구매하기");
}
@Override
public void order() {
System.out.println("고객 판매 주문");
}
}
package interfaceex;
public class CustomerTest {
public static void main(String[] args) {
Customer customer = new Customer();
Buy buyer = customer;
buyer.buy();
Sell seller = customer;
seller.sell();
customer.order();
buyer.order();
seller.order();
//고객 판매 주문, 전부 overriding된 메서드가 불림
}
}
인터페이스 상속
인터페이스 간에도 상속이 가능
구현 코드의 상속이 아니므로 형 상속(type inheritance)라고 함
package interfaceex;
public interface X {
void X();
}
package interfaceex;
public interface Y {
void Y();
}
package interfaceex;
public interface MyInterface extends X, Y{
void myMethod();
}
package interfaceex;
public class MyClass implements MyInterface{
@Override
public void X() {
System.out.println("x()");
}
@Override
public void Y() {
System.out.println("y()");
}
@Override
public void myMethod() {
System.out.println("myMethod()");
}
public static void main(String[] args) {
MyClass myClass = new MyClass();
X xClass = myClass;
xClass.X();
}
}
인터페이스 구현과 클래스 상속 함께 사용하기
실제 프레임워크(스프링, 안드로이드)를 사용하면 클래스를 상속받고 여러 인터페이스를 구현하는 경우가 있음
package bookshelf;
public interface Queue {
void enQueue(String title);
String deQueue();
int getSize();
}
package bookshelf;
import java.util.ArrayList;
public class Shelf {
protected ArrayList<String> shelf;
public Shelf() {
shelf = new ArrayList<String>();
}
public ArrayList<String> getShelf() {
return shelf;
}
public int getCount() {
return shelf.size();
}
}
package bookshelf;
public class BookShelf extends Shelf implements Queue{
@Override
public void enQueue(String title) {
shelf.add(title);
}
@Override
public String deQueue() {
return shelf.remove(0);
}
@Override
public int getSize() {
return getCount();
}
}
package bookshelf;
public class BookShelfTest {
public static void main(String[] args) {
Queue shelfQueue = new BookShelf();
shelfQueue.enQueue("루팽구1");
shelfQueue.enQueue("루팽구2");
shelfQueue.enQueue("루팽구3");
System.out.println(shelfQueue.deQueue());
System.out.println(shelfQueue.deQueue());
System.out.println(shelfQueue.deQueue());
}
}