코드 그라데이션

후발대 10일차 개념별 클래스 분류 본문

Java/후발대

후발대 10일차 개념별 클래스 분류

완벽한 장면 2023. 1. 23. 16:07

수업 순서대로 코드 및 설명 보충

개념설명

    추상클래스, 추상메서드
  추상클래스는 미완성 설계도를 가진 클래스라고 생각하면 된다
  추상클래스란 추상 메서드를 선언할 수 있는 클래스. 불완전 형태
(설계만 되어있고, 구현체가 없는 것)
접근제어자, 리턴타입, 메소드명(파라메터)는 있지만 중괄호 블록 없음.
예) public int sum(int a, int b);
  추상: 여러 가지 사물이나 개념에서 공통되는 특성이나 속성 따위를 추출하여 파악하는 작용.
  예 ) 정녕 해가 있다면 그것은 당신들이 지금 알고 있는 것이 아니라 그 이름이 가진 어떤 추상일 뿐이오.  (출처: 네이버 지식사전)

  컴퓨터 과학에서의 추상화는 복잡한 자료, 모듈, 시스템 등으로부터 핵심적인 개념 또는 기능을 간추려 내는 것을 말한다.
  객체 지향 관점에서의 추상화는 클래스를 정의할 때, 불필요한 부분들을 생략하고 객체의 속성 중 중요한 것에만 중점을 두어 개략화 하는 것, 즉 클래스들의 중요하고 공통된 성질들을 추출하여 슈퍼 클래스를 선정하는 개념이다.
  추상클래스는 불완전한 형태를 가진 클래스의 형태로, 미완성된 부분을 가지고 있다.
  추상클래스 자체로는 인스턴스를 생성할 수 없다.(상속받는 자식 클래스 없이는 그 자체로 불가능)
- 추상화를 통해 잘 설계했다면 여러개의 클래스를 정의했을 때, 중복 코드가 현저히 줄어들 것 이다.
-> 코드가 간결해지기 때문에 생산성 증가, 가독성 증가, 에러 감소, 유지 보수시 시간 단축 등의 효과!
-> 잘 만들어진 슈퍼 클래스 덕분에 코드의 재사용성이 증가한다.

  인터페이스는 하나도 만들어 지지않은 “기본 설계도”로 볼 수 있다.
  추상클래스와 마찬가지로 객체의 인스턴스를 생성할 수 없다.
- 추상 클래스는 추상 메소드뿐만 아니라 생성자, 필드, 일반 메소드도 포함할 수 있지만 인터페이스는 오로지 추상 메소드와 상수만을 포함할 수 있다.
- 그럼 추상클래스만 쓰지 인터페이스를 왜 써? 왜? why? -> 자바는 클래스를 통한 다중 상속은 지원하지 않지만 클래스와 인터페이스를 통한 다중 상속은 지원하기 때문!
- 추상클래스나 인터페이스에 구현한 추상메소드들은 상속받는 클래스들에게 강제성을 부여! -> 꼭 오버라이딩 해서 사용해야만 함.

----------------------------------------------------------------------------------------------

  인터페이스 vs 추상클래스
    - 인터페이스
    1. 구현하려는 객체의 동작의 명세
    2. 다중 상속 가능
    3. implements를 이용하여 구현(키워드)
    4. 메소드 시그니처(이름, 파라미터, 리턴 타입)에 대한 선언만 가능

    - 추상클래스
    1. 클래스를 상속받아 이용 및 확장을 위함
    2. 다중 상속 불가능 , 단일 상속
    3. extends를 이용하여 구현(키워드)
    4. 추상메소드에 대한 구현 가능
    5. 추상클래스 자체로는 객체 생성이 불가능


인터페이스와 추상 클래스의 차이
추상클래스(Abstract Class)는 인터페이스의 역할도 하면서 클래스의 기능도 가지고 있는 자바의 돌연변이 같은 클래스이다. 혹자는 추상클래스는 인터페이스로 대체하는것이 좋은 디자인이라고도 얘기한다. 추상 클래스는 인터페이스와는 달리 일반 클래스처럼 객체변수, 생성자, private 메서드 등을 가질 수 있다.

private 메서드는 클래스 내에서만 사용되는 메서드로 다른 클래스에서 호출이 불가능하다.

 

 

10-1. Bird

- 추상 클래스

package Prac10;

abstract class Bird {
    //1) 변수 선언
    private int x, y, z;

    //4) 날아가는 메서드를 구현
    void fly(int x, int y, int z) {
        printLocation(); // 현재 위치
        System.out.println("이제, 이동합니다!");

        this.x = x;
        this.y = y;
        // 받은 축으로 이동

        if(flyable(z)) { // 날 수 있는지 여부를 따짐.
            this.z = z;
        } else {
            System.out.println("그 높이로는 날 수 없습니다...");
        }
        printLocation(); // 이동한 위치
    }


    //3) 날 수 있느냐 없느냐를 불린 타입으로 선언
    abstract boolean flyable(int z); // 원래 중괄호로 실행문장이 들어가야 하는데, Body가 없으므로 추상클래스로 정의된다.
    // 상속받은 클래스에서 반드시 구현되어야만이 정상적으로 구동이 된다.

    // 2) 위치 메서드 구현
    public void printLocation() {
        System.out.println("현재 위치:  ("+x+", "+y+", "+z+")");
    }
}

//Bird 상속받는 Pigeon(비둘기) 클래스 구현
class Pigeon extends Bird { //상속을 받으면 처음에 빨간줄이 뜬다. 이유는 미 구현된 무언가가 있기 때문에 반드시 구현하라는 뜻.

    @Override
    boolean flyable(int z) {
        return z<10000;
    }
}

// 날 수 없는 공작새 클래스 생성
class Peacock extends Bird {
    @Override
    boolean flyable(int z) {
        return false; // 날 수 없으므로 false 반환.
    }
}
public class Day10 {
    public static void main(String[] args) {

        /*
        cf. 첫 줄을 상속받은 자동객체로 구현하는 게 아니라, Bird pigeon = new Pigeon();으로 해도 가능하다!
        두번째 줄도, Bird peacock = new Peacock(); 도 가능하다.
        그 이유는 추상클래스에서 정의해 놓은 것을 자동객체에서 다 구현을 해 놓았기 때문에
        추상클래스 타입은 부모 클래스 타입으로 객체 생성이 가능하다!
        다형성 측면.
         */

        Pigeon pigeon = new Pigeon();
        Peacock peacock = new Peacock();

        System.out.println("====비둘기====");
        pigeon.fly(1,1,3);
        System.out.println();

        System.out.println("====공작새====");
        peacock.fly(1,1,3);
        System.out.println();

        System.out.println("====비둘기====");
        pigeon.fly(3,3,30000);

    }
}
/*
정리
: 추상클래스는 미구현된 내용을 가지고 있고, 그것을 상속받아서 사용하게 된다면, 사용할 때에 반드시 미구현된 내용은 구현해줘야 한다.
+ 구현을 할 때 부모 타입은 추상 클래스의 타입으로 쓸 수 있다.

다만, 위에서 Bird 타입으로는 인스턴스를 만들 수 없다. 추상클래스는 미구현된 부분이 있어서 그 자체로는 객체를 만들 수 없기 때문.
 */

 

 

10-2. Bird2

- 인터페이스

 

package Prac10;

interface Bird2 {

    void fly2(int x, int y, int z);


}

class Pigeon2 implements Bird2 {
    private int x, y, z;

    @Override
    public void fly2(int x, int y, int z) {
        printLocation2();
        System.out.println("지금부터 날아갑니다.");
         this.x = x;
         this.y = y;
         this.z = z;
         printLocation2();

    }

    public void printLocation2() {
        System.out.println("현재 위치:  ("+x+", "+y+", "+z+")");

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

        //Pigeon2 pigeon2 = new Pigeon2(); 가능
        Bird2 pigeon = new Pigeon2();
        pigeon.fly2(1,2,3);

    }
}
/*
인터페이스가 더 생략된 부분이 많다 => 즉, 구현해야 할 부분이 많다는 거지.
예를 들어 상수를 가져왔을 때, 상수 내용도 변경할 수 없다.
인터페이스도 추상클래스와 동일하게 미구현된 (Body 가 없는) 추상 메서드를 가지게 되고,
이럴 경우에는 자손 클래스에서 동작을 보장할 수 있도록 구현을 꼭 해줘야 한다는 특징을 지닌다.
 */

 

 

10-3. 추상클래스 실습예제, Animal

package Prac10;

// 1) 추상클래스 실습예제 : Animal

abstract class Animal10 {
    String name;
    int age;
    String howling; // 이 울음 소리는 자손 클래스에서 정의하도록 하겠다.

    public Animal10(String name, int age) {
        this.name = name;
        this.age = age;
    }

    void howl() {
        System.out.println(this.howling + " 내 이름은 " + this.name + ", " + age + "살 " + "이다!!!");
    }

    //동물들마다 매력포인트가 있다고 해보자 동물들마다 특징을 줄 거기 때문에 abstract 타입으로 선언을 하고, 자손 클래스에서 구현함
    abstract void charming();
    // 추상 메서드! => 상속받는 클래스는 무조건 오버라이딩 해야 한다. => 강제성 부여.
}

class Cat10 extends Animal10 {

    public Cat10(String name, int age) {
        super(name, age);
        this.howling = "야옹!";
    }

    @Override //매력포인트 드디어 구현
    void charming() {
        System.out.println("부비부비");
    }
}

class Dog10 extends Animal10 {

    public Dog10(String name, int age) {
        super(name, age);
        this.howling = "멍멍!";
    }

    @Override
    void charming() {
        System.out.println("배 까고 드러눕기!");
    }
}

public class Day10_3_Animal {
    public static void main(String[] args) {
        Cat10 cat = new Cat10("고양고양이", 5);
        Dog10 dog = new Dog10("바둑이", 10);

        cat.howl();
        dog.howl();

        cat.charming();
        dog.charming();
    }
}
/*
즉, 이것은 Animal에서 기본적인 기능만 구현을 해놓고, 나머지는 상속받은 자손클래스에서 동물들의 매력을 집어넣어서
생성자를 통해 객체를 생성할 수 있게 되고, 각각의 메서드들을 구현할 수 있게 마저 구현을 한 것.
 */

 

 

10-4. 추상클래스 실습예제 2)

- 도형의 넓이 구하기

package Prac10;

// 추상클래스 실습 예제 2) 도형의 면적 구하기
/*
면적(Figure)라는 클래스는 추상클래스다.
가로와 세로를 파라미터로 받아 넓이(area)를 구하는 추상메서드가 있다.

사각형은 면적을 상속받아 넓이를 구하는 추상메서드를 완성합니다.
삼각형도 위와 동일 ...""  ""

메인클래스에서 삼각형과 사각형 객체를 생성하여
두 수를 인자로 넘겨받아 넓이를 구해 봅니다.
 */

abstract class Figure10 {    // 추상 클래스

    abstract void area(int a, int b); // 추상 메서드
// 넓이 구하는 공식을 바디(실행코드 부분)에 알맞게 구현.

}



// 사각형 클래스

class Square10 extends Figure10 {

    void area(int a, int b) {

        System.out.println("사각형의 넓이 : "+(a*b));

    }

}



class Triangle10 extends Figure10 {

    void area(int a, int b) {

        System.out.println("삼각형의 넓이 : "+(a*b/2));

    }

}



public class Day10_4_Figure {

    public static void main(String[] args) {

        Square10 square = new Square10();

        square.area(10, 7);



        Triangle10 triangle = new Triangle10();

        triangle.area(15, 8);

    }

}

 

 

10-5. 인터페이스 실습예제,

택시 미터기

Meter

package Prac10;
// 1) 인터페이스 실습예제 : 택시미터기

//Meter(택시 미터기)인터페이스는 start와 stop이라는 추상 메소드를 가지고 있습니다.
// stop메소드는 달린 거리에 해당하는 값(distance)를 매개변수로 받아
// 요금을 반환하는 메소드입니다.
// Meter인터페이스를 구현하는 택시 클래스를 완성해 보세요.
// 요금은 distance x 2로 계산이 됩니다. (stop 메서드)

public interface Meter10 {

        public int BASE_FARE = 3000;     // 기본요금(인터페이스에 정의한 변수는 상수라서 변경할 수 없다.)

        public abstract void start();
        public abstract int stop(int distance);

}

 

Taxi

package Prac10;

public class Taxi10 implements Meter10 {
    //Meter10 인터페이스의 start와 stop 메서드를 구현해야 한다.

    @Override
    public void start() {
        System.out.println("운행을 시작합니다.");

    }

    @Override
    public int stop(int distance) {
        int fare = BASE_FARE + distance * 2; //요금 책정하는 방식. 즉 운행이 종료되면 요금을 알 수 있도록 로직을 작성한다.
        System.out.println("운행을 종료합니다. 요금은 " + fare + "원 입니다.");
        return fare;
    }
}

 

미터기 실행 클래스

package Prac10;

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

        Taxi10 taxi = new Taxi10();
        taxi.start();
        taxi.stop(20);
    }
}

 

 

10-6. 인터페이스 실습 예제 2)

- 자율 주행차

package Prac10;

interface OperateCar10 {
    void start();
    void stop();
    void setSpeed(int speed);
    void turn(int degree);
}

class AutoCar10 implements OperateCar10 {
    @Override
    public void start() {
        System.out.println("자동차가 출발합니다.");
    }

    @Override
    public void stop() {
        System.out.println("자동차가 멈춥니다.");
    }

    @Override
    public void setSpeed(int speed) {
        System.out.println("자동차가 속도를 " + speed + "km/h 로 바꿉니다.");
    }

    @Override
    public void turn(int degree) {
        System.out.println("자동차가 방향을 " + degree + "도 만큼 바꿉니다.");
    }
}

public class Day10_6_OperateCar { // 인터페이스는 그 기능을 꼭 구현할 것을 강제하므로, 동작을 할 거라고 보장이 가능하다.
    public static void main(String[] args) {
        OperateCar10 car = new AutoCar10();
        car.start();
        car.setSpeed(70);
        car.turn(30);
        car.stop();
    }

}
728x90
Comments