예제 코드 분석

하위 태스크 설명

s0505 ~ s0509 상속/인터페이스 구조 파악

  • s0505:
    • Animal Dog HouseDog의 상속 관계를 보인다.
    • HouseDogDogsleep 메서드를 오버라이딩한다.
    • HouseDoghour 매개 변수를 더한 sleep 메서드를 구현하여 메서드 오버로딩이 발생한다.
  • s0506:
    • s0505의 분석 내용과 같다.
    • HouseDogString 자료형의 매개 변수를 지닌 생성자, int 자료형의 매개 변수를 지닌 생성자가 존재하여 생성자 오버로딩이 발생한다.
  • s0507:
    • TigerLionPredator 인터페이스를 구현한다.
    • TigerLionAnimal의 파생 클래스이자 Predator 인터페이스의 구현체이므로 다형성이 발생한다.
  • s0508:
    • 다중 상속이 가능한 인터페이스의 특징을 이용해 Predator 인터페이스와 Barkable 인터페이스를 모두 상속한 BarkablePredator 인터페이스를 생성한다.
    • Lion 클래스는 BarkablePredator 인터페이스를 구현하여 Predator 인터페이스와 Barkable 인터페이스의 특징을 모두 갖는다.

상속 구조 설계

하위 태스크 설명

상위/하위 클래스 설계

DogCat은 기본 클래스 Animal을 상속한 파생 클래스다. DogCat은 자신만의 추가 속성을 지니며, AnimalprintInfo 메서드를 오버라이딩한다.

public class Animal {  
    private long age;  
    private String name;  
    private double weight;  
  
    public static void main(String[] args) {  
        Dog nana = new Dog("나나", 3, 5.5, "사과");  
        Cat dada = new Cat("다다", 4, 4.8, "바람개비");  
  
        nana.printInfo();  
        dada.printInfo();  
    }  
  
    Animal(String name, long age, double weight) {  
        this.name = name;  
        this.age = age;  
        this.weight = weight;  
    }  
  
    void eat() {  
        System.out.printf("%s이(가) 먹이를 먹습니다.\n", this.name);  
    }  
  
    void sleep() {  
        System.out.printf("%s이(가) 잠을 잡니다.\n", this.name);  
    }  
  
    void printInfo() {  
        System.out.printf("%s의 정보:\n", this.name);  
        System.out.printf("    %s: %d\n", "나이", this.age);  
        System.out.printf("    %s: %f\n", "무게", this.weight);  
    }  
}  
  
class Dog extends Animal {  
    private String favoriteFeed;  
  
    Dog(String name, long age, double weight, String favoriteFeed) {  
        super(name, age, weight);  
        this.favoriteFeed = favoriteFeed;  
    }  
  
    @Override  
    void printInfo() {  
        super.printInfo();  
        System.out.printf("    %s: %s\n", "좋아하는 먹이", this.favoriteFeed);  
    }  
}  
  
class Cat extends Animal {  
    private String favoriteToy;  
  
    Cat(String name, long age, double weight, String favoriteToy) {  
        super(name, age, weight);  
        this.favoriteToy = favoriteToy;  
    }  
  
    @Override  
    void printInfo() {  
        super.printInfo();  
        System.out.printf("    %s: %s\n", "좋아하는 장난감", this.favoriteToy);  
    }  
}

다형성 예제 작성

하위 태스크 설명

부모 타입 배열/리스트 사용

이전의 Animal 클래스 예제에서 Animal 클래스의 main 메서드를 다음과 같이 수정한다. Cat 클래스와 Dog 클래스의 인스턴스를 Animal 자료형의 요소를 갖는 ArrayList에 저장한다. 이후 ArrayList를 순회하며 각 요소가 공통적으로 가지고 있는 printInfo 메서드를 호출한다.

import java.util.ArrayList;  
import java.util.Arrays;
 
// ...
 
public class Animal {
	// ...
	
	public static void main(String[] args) {  
	    Dog nana = new Dog("나나", 3, 5.5, "사과");  
	    Cat dada = new Cat("다다", 4, 4.8, "바람개비");  
	    Dog rara = new Dog("라라", 6, 5.2, "딸기");  
	    Cat mama = new Cat("마마", 2, 4.9, "공");  
	  
	    ArrayList<Animal> animals = new ArrayList<>(Arrays.asList(nana, dada, rara, mama));  
	    for (Animal animal: animals) {  
	        animal.printInfo();  
	    }  
	}
	
	// ...
}
 
// ...

인터페이스 정의, 구현체 작성, 의존성 역전 적용

하위 태스크 설명

  • 공통 동작 인터페이스 설계
  • 인터페이스 구현 클래스 여러 개 작성
  • 클라이언트가 인터페이스에만 의존하도록 수정

PrintStrategy 인터페이스는 문자열 내용을 출력하는 print 메서드를 포함한다.

ConsolePrintStrategy 클래스와 FilePrintStrategy 클래스는 print 메서드를 완성하여 PrintStrategy 인터페이스를 구현한다.

Printer 클래스는 생성자를 통해 PrintStrategy 자료형의 객체를 주입 받는다. Printer 클래스의 print 메서드는 주입 받은 PrintStrategyprint 메서드를 실행한다. 이런 구조를 통해 클래스 간의 강한 결합을 낮추고 유연하게 동작을 변경할 수 있다.

import java.io.IOException;  
import java.nio.file.Files;  
import java.nio.file.Path;  
  
interface PrintStrategy {  
    void print(String content);  
}  
  
class ConsolePrintStrategy implements PrintStrategy {  
    @Override  
    public void print(String content) {  
        System.out.println(content);  
    }  
}  
  
class FilePrintStrategy implements PrintStrategy {  
    Path path;  
  
    FilePrintStrategy(String path) {  
        this.path = Path.of(path);  
    }  
  
    @Override  
    public void print(String content) {  
        try {  
            Files.writeString(this.path, content);  
        } catch (IOException e) {  
            System.out.println("파일에 내용을 기록할 수 없습니다.");  
        }  
    }  
}  
  
class Printer {  
    PrintStrategy strategy;  
  
    Printer(PrintStrategy strategy) {  
        this.strategy = strategy;  
    }  
  
    void print(String content) {  
        this.strategy.print(content);  
    }  
}  
  
public class PrintSample {  
    public static void main(String[] args) {  
        String content = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";  
  
        Printer consolePrinter = new Printer(new ConsolePrintStrategy());  
        Printer filePrinter = new Printer(new FilePrintStrategy("sample.txt"));  
  
        consolePrinter.print(content);  
        filePrinter.print(content);  
    }  
}