사이먼's 코딩노트

[Java] 클래스와 메서드를 활용한 문제풀이 본문

Java/Java

[Java] 클래스와 메서드를 활용한 문제풀이

simonpark817 2024. 2. 6. 14:13
  • 클래스와 메서드 그리고 상속을 통한 문제를 요구사항에 맞춰서 풀어보자.

 

[문제]

문제 : 다음 요구사항에 맞는 클래스와 메서드를 생성해보세요.

 

요구사항 1 : 오리 생성하고 날아가는 능력을 부여하세요.

요구사항 2 : 청둥오리와 흰오리를 생성하고 날아가는 능력을 부여하세요.

요구사항 3 : 오리 계열(오리, 청둥오리, 흰오리)의 클래스에 '날다' 메서드가 중복되지 않도록 하세요.

요구사항 4 : 고무오리를 생성하고 날아가는 능력을 부여하세요.

요구사항 5 : 고무오리 계열에게 날아가는 능력을 뺏어주세요.

요구사항 6 : 고무2오리를 추가 생성해주세요.

요구사항 7 : 고무오리 계열의 클래스에 '날다' 메서드가 중복되지 않도록 하세요.

요구사항 8 : 로봇오리를 생성하여 오리계열과 고무오리계열의 능력을 반반씩 부여하세요.

public class Main {
    public static void main(String[] args) {
        오리 a오리 = new 오리();
        a오리.날다();
        a오리.수영하다(); // 오리가 물갈퀴로 수영합니다.

        System.out.println("== 청둥오리 ==");
        청둥오리 a청둥오리 = new 청둥오리();
        a청둥오리.날다(); // 오리가 날개로 날아갑니다.
        a청둥오리.수영하다(); // 오리가 물갈퀴로 수영합니다.

        System.out.println("== 흰오리 ==");
        흰오리 a흰오리 = new 흰오리();
        a흰오리.날다(); // 오리가 날개로 날아갑니다.
        a흰오리.수영하다(); // 오리가 물갈퀴로 수영합니다.

        System.out.println("== 고무오리 ==");
        고무오리 a고무오리 = new 고무오리();
        a고무오리.날다(); // 저는 못 날아요 ㅠㅠ
        a고무오리.수영하다(); // 오리가 물에 둥둥 떠다닙니다.

        System.out.println("== 고무2오리 ==");
        고무2오리 a고무2오리 = new 고무2오리();
        a고무2오리.날다(); // 저는 못 날아요 ㅠㅠ
        a고무2오리.수영하다(); // 오리가 물에 둥둥 떠다닙니다.

        System.out.println("== 로봇오리 ==");
        로봇오리 a로봇오리 = new 로봇오리();
        a로봇오리.날다(); // 오리가 날개로 날아갑니다.
        a로봇오리.수영하다(); // 오리가 물에 둥둥 떠다닙니다.
    }
}

class 오리 {
    void 날다() {
        System.out.println("오리가 날개로 날아갑니다.");
    }
    void 수영하다() {
        System.out.println("오리가 물갈퀴로 수영합니다.");
    }
}

class 청둥오리 extends 오리 {
}

class 흰오리 extends 오리 {
}

class 고무오리 extends 오리 {
    void 날다() {
        System.out.println("저는 날 수 없어요. ㅜㅠ");
    }
    void 수영하다() {
        System.out.println("오리가 물에 둥둥 떠다닙니다.");
    }
}

class 고무2오리 extends 고무오리 {
}

class 로봇오리 extends 오리 {
    void 수영하다() {
        System.out.println("오리가 물에 둥둥 떠다닙니다.");
    }
}
  • 클래스를 생성하고 '날다' 와 '수영하다' 메서드를 만드는 것은 비교적 쉬운 작업이다.
  • 요구사항 3처럼 오리 계열의 메서드가 중복되지 않게 하도록 하기 위해선 '오리' 라는 클래스에 모든 종류의 오리가 포함된다고 상식적으로 생각을 하면 접근이 쉽다.
  • 청둥오리와 흰오리에게는 따로 메서드를 생성하지 않고 'extends 오리' 를 통한 상속을 부여하면 메서드 중복이 일어나지 않는다.
  • 고무오리는 오리 계열은 맞지만 '날다'와 '수영하다' 의 능력이 오리와는 정반대이기 때문에 상속은 시키되, 오버라이딩을 통해서 메서드를 재정의 해줘야한다.
  • 고무2오리는 오리 계열이 맞지만, 능력을 따졌을 때 고무오리의 능력을 그대로 상속받기 때문에 'extends 고무오리' 를 통해 오리가 아닌 고무오리에게 상속을 받는다.
  • 로봇오리는 오리의 '날다' 고무오리의 '수영하다' 의 능력을 각각 부여 받아야한다.
  • 로봇오리의 근원은 오리이기 때문에 'extends 오리' 를 통해 오리의 '날다' 능력을 상속받고, 오버라이딩을 통해서 '수영하다' 의 능력을 재정의 해줘야한다.

 

 

[문제2]

문제 : 다음 요구사항에 맞는 매개변수를 활용한 클래스와 메서드를 생성해보세요.

 

요구사항 1 : 칼과 활 같은 무기의 공격 능력은 중복되지 않도록 하세요.

요구사항 2 : 전사는 총 3명이고 같은 객체 변수를 통해 생성하고 인자와 매개변수를 통해 3명의 공격성을 표현하세요.

public class Main {
    public static void main(String[] args) {

        무기 a무기 = new 칼();
        a무기.공격();
        // 출력 : 칼로 공격합니다.


        전사 a전사 = new 전사();

        a전사.공격("브라이언", "칼");
        // 브라이언이(가) 칼(으)로 공격합니다.
        a전사.재공격();
        // 브라이언이(가) 칼(으)로 공격합니다.

        a전사.공격("필립", "창");
        // 필립이(가) 창(으)로 공격합니다.
        a전사.재공격();
        // 브라이언이(가) 칼(으)로 공격합니다.

        a전사.공격("마크", "지팡이");
        // 마크(가) 지팡이(으)로 공격합니다.
        a전사.재공격();
        // 브라이언이(가) 칼(으)로 공격합니다.

    }
}

class 전사 {
    String last_name;
    String last_weapon;
    void 공격(String name, String weapon) {
//      전역변수와 지역변수(매개변수)의 이름이 똑같을 때는 this를 붙혀주는 것이 좋다.
//        this.last_name = name; 와 같이
        last_name = name;
        last_weapon = weapon;
        System.out.println(name + "이(가) " + weapon + "(으)로 공격합니다.");
    }
    void 재공격() {
        System.out.println(last_name + "이(가) " + last_weapon + "(으)로 공격합니다.");
    }
}
class 무기 {
   void 공격() {
       System.out.println("칼로 공격합니다.");
   }
}

class 칼 extends 무기 {
    void 공격() {
        System.out.println("칼로 공격합니다!!!!");
    }
}

class 활 extends 무기 {

}
  • 'a무기' 는 무기이지만 그 중에서도 칼 타입의 무기로 객체 변수가 생성되었다.
  • 칼은 무기에 속하기 때문에 extends를 통한 상속의 개념을 가져야한다.
  • 무기와 칼 두 가지의 클래스를 모두 생성해주고 공격() 이라는 메서드는 무기 클래스에서는 반드시 생성해줘야 한다.
  • 칼 클래스에만 공격() 메서드를 작성하면 안되는 이유는 a무기라는 객체 변수는 상속을 통해 무기 객체와도 연결된 리모콘을 가지고 있기 때문에 무기 클래스에도 공격() 메서드를 작성해야만 한다.
  • 한마디로 무기와 칼은 서로 상속의 관계이기 때문에 두 객체가 반드시 같은 형태를 유지해야한다.
  • 하지만 칼 클래스에서 같은 능력이라도 다른 의미를 부여하고 싶다면 오버라이딩을 통해 재정의가 가능하다.

 

  • 전사 클래스에는 공격() 이라는 메서드와 재공격() 이라는 메서드가 정의되어있다.
  • 공격() 메서드는 매개변수로 name과 weapon의 값을 받아오고 재공격() 메서드는 매개변수가 따로 존재하지 않는다.
  • main 메서드에서 재공격() 메서드를 호출할 때는 마지막 공격 방식을 기억하여 바로 직전에 공격을 시도했던 대상의 정보가 출력된다.
  • 예를 들어 첫번째 a전사.공격()을 통해 브라이언이 칼로 공격한 출력문이 나왔다면 해당 공격 방식을 기억해놨다가 바로 아래 a전사.재공격()을 호출하면 직전 공격과 똑같이 브라이언이 칼로 공격한 출력문이 나오게된다.
  • 위와 같은 메서드를 구현하는 방법은 공격() 메서드에서 매개변수(지역변수)로 받은 name과 weapon을 해당 클래스 안에서 전역변수인 last_name과 last_weapon에 값을 저장하고 출력문에서 last_name과 last_weapon을 출력하면된다.
  • 위 코드에선 공격() 메서드와 재공격() 메서드에서 모두 출력문을 출력하지만, 해당 과정이 귀찮다면 공격() 메서드에서 굳이 출력문을 작성하지 않고 재공격(); 으로 메서드를 호출하면 출력문은 재공격() 메서드에서 한 번만 사용할 수 있다.

 

 

[문제3]

문제 : 전사가 들고 있는 무기에 의해서 서로 다른 공격형태를 보이도록 해보세요.

 

요구사항 1 : 메서드에 매개변수를 포함하지 않고 구현해보세요.

public class Main {
    public static void main(String[] args) {
        전사 a전사 = new 전사();

        String 이름 = "칸";
        a전사.이름 = 이름;
        a전사.나이 = 20;
        a전사.자기소개();

        a전사.나이++;
        a전사.자기소개();

        a전사.나이 = 30;
        a전사.이름 = "카니";
        a전사.자기소개();

        a전사.a무기 = new 활();
        a전사.공격();
        // 출력 : 카니가 활로 공격합니다.

        a전사.a무기 = new 칼();
        a전사.공격();
        // 출력 : 카니가 칼로 공격합니다.
    }
}

class 전사 {
    String 이름;
    int 나이;
    무기 a무기;

    void 자기소개() {
        System.out.println("안녕하세요. 저는 " + this.나이 + "살 " + this.이름 + " 입니다.");
    }

    void 공격() {
        a무기.공격자명 = 이름;
        a무기.작동();
    }
}

class 무기 {
    String 공격자명;
    void 작동() {
    }
}

class 칼 extends 무기 {
    void 작동() {
        System.out.printf("%s가 칼로 공격합니다.\n", 공격자명);
    }
}

class 활 extends 무기 {
    void 작동() {
        System.out.printf("%s가 활로 공격합니다.\n", 공격자명);
    }
}
  • Main 메서드에서 [전사 a전사 = new 전사()] 를 통해 new 전사() 객체를 하나 생성하고 a전사와 서로 리모콘으로 연결되어있는 것을 알 수 있다.
  • 전사는 각 전사의 이름을 담을 수 있는 String 이름과 나이를 담을 수 있는 int 나이를 생성했고 자기소개를 할 수 있는 자기소개() 메서드를 생성하였다.
  • 그리고 Main 함수에서는 위에서부터 차례로 각 이름과 나이에 해당 값을 저장하였다.
  • 칸과 카니가 차례로 자기소개를 통해 출력문을 출력하고 a무기라는 인스턴스 변수를 이용해서 칼과 활이라는 객체를 새로 생성하였다.

 

  • 먼저, 칼과 활이라는 객체를 생성하기 위해서는 칼과 활이라는 클래스를 생성해야된다.
  • 칼과 활 클래스를 생성했음에도 에러가 발생하는 이유는 인스턴스 변수인 a무기의 타입을 아직 정의하지 못했기 때문이다.
  • a무기는 우리가 알고있는 String이나 int 등의 타입으로 정의할 수 없기 때문에 칼 또는 활 타입으로 정의해야한다.
  • 하지만, 위 코드에서는 a무기 인스턴스 변수 하나로 칼과 활 모두에게 연결되는 리모콘을 생성해야되기 때문에 어느 한쪽으로 타입을 정하는 데는 한계가 있다.
  • 우리는 이 문제를 해결하기 위해 칼과 활을 모두 포용하는 '무기'라는 클래스를 생성해야한다.
  • 무기 클래스를 만들게 되면 a전사가 들고있는 무기에 의해서 서로 다른 공격형태를 보일 수 있다.
  • 이 때, 칼과 활은 우리 상식선에서 모두 무기에 포함되기 때문에 extends를 이용해서 서로 상속의 관계로 정의한다.

 

  • 그 다음은 a전사.공격() 메서드를 통해 a전사가 가지고 있는 칼 또는 활로 공격을 성공했다는 출력문을 출력해야한다.
  • 예상 출력문에서 공격을 하는 공격자는 이름 변수(a전사.이름)에 마지막으로 저장된 카니이다.
  • 공격() 메서드는 a전사를 통해 호출이 가능하기 때문에 전사 클래스에서 생성해야만 에러가 발생하지 않는다.
  • 그 다음은 공격() 메서드에서 바로 출력문을 작성하는 것이 아니라 원하는 무기별로 공격이 가능하게 a무기.작동() 이라는 메서드를 호출한다.
  • a무기.작동() 메서드가 호출되려면 a무기의 실제 타입인 무기에도 작동() 이라는 메서드가 존재해야하고 상속받는 칼과 활에도 작동() 메서드를 작성하여 각 무기 종류에 맞게 오버라이딩을 해준다.

 

  • 마지막으로 저장된 공격자명 이름(카니)을 매개변수 없이 작동() 메서드를 통해 출력을 하기 위해서 무기 클래스에서 String 공격자명을 선언해준다.
  • 무기에서 선언된 공격자명 인스턴스 변수는 칼과 활 클래스에서도 상속이 되기 때문에 출력문에서 변수 호출이 가능하다.
  • 우리는 공격자명 인스턴스 변수에 전사에서 저장한 이름 인스턴스 변수를 담아주기만 하면 작업이 끝난다.
  • 전사의 공격() 메서드에 [a무기.공격자명 = 이름] 과 같이 작성하면 Main 메서드에서 마지막으로 저장된 이름인 카니가 무기 타입에서 선언한 공격자명에 저장된다.
반응형

'Java > Java' 카테고리의 다른 글

[Java] 생성자 문제풀이  (1) 2024.02.14
[Java] 캐스팅 / 생성자  (2) 2024.02.14
[Java] 상속 / 오버로딩 / 오버라이딩  (0) 2024.02.02
[Java] 클래스와 메서드(2)  (0) 2024.02.02
[Java] 클래스와 메서드(1)  (2) 2024.01.29