JAVA 영화 예매 프로그램, 상속실습, 추상메소드

JAVA 영화예매 프로그램

MovieReservation 클래스

package MovieReservation;

public class SeatInfo {
    private String[][] seat = new String[3][5];    
}

MovieVO 클래스

package MovieReservation;

public class MovieVo {
    private String movieName;
    private int runtime;
    private String genre;
    private String director;
    private int audience;

    public MovieVo(String movieName, int runtime, String genre, String director, int audience) {
        super();
        this.movieName = movieName;
        this.runtime = runtime;
        this.genre = genre;
        this.director = director;
        this.audience = audience;
    }

    public String getMovieName() {
        return movieName;
    }

    public void setMovieName(String movieName) {
        this.movieName = movieName;
    }

    public int getRuntime() {
        return runtime;
    }

    public void setRuntime(int runtime) {
        this.runtime = runtime;
    }

    public String getGenre() {
        return genre;
    }

    public void setGenre(String genre) {
        this.genre = genre;
    }

    public String getDirector() {
        return director;
    }

    public void setDirector(String director) {
        this.director = director;
    }

    public int getAudience() {
        return audience;
    }

    public void setAudience(int audience) {
        this.audience = audience;
    }

    @Override
    public String toString() {
        return movieName + "\t " + runtime + "분\t  " + genre + "\t "
                + director + "\t" + audience + "명";
    }


}

 

 

Reservation 클래스

package MovieReservation;

public class Reservation {
    private String[][] seat;    
    private String seatNum;
    private int reservationSeatNum;
    private MovieVo movie;

    public Reservation() {
        super();
        movie = new MovieVo("살인자의 기억법", 118, "공포, 스릴러", "원신연", 15);
        seat = new String[3][5];
        reservationSeatNum = 1000;
    }

    public MovieVo todayShow() {
        return movie;
    }

    public String SeatCheck(String seat, int j) {
        if (seat == null) {
            return j + "[====]";
        } else {
            return j + "[XXXX]";
        }
    }
}

MovieMain 클래스

package MovieReservation;

import java.util.Scanner;

public class MovieMain {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String[][] seat = new String[3][5];
        int reservationSeatNum = 1000;
        Reservation reser = new Reservation();

        while (true) {
            System.out.print("1.오늘의 영화 2.좌석보기 3.영화예매 4.취소 5.종료 : ");
            int choice = sc.nextInt();

            if (choice == 1) {
                System.out.println("================= 오늘의 영화 =================");
                System.out.println("제목 \t\t\t 상영시간  장르 \t\t 감독 \t 관람가");
                System.out.println(reser.todayShow());
                System.out.println("===========================================");
            } else if (choice == 2) {
                for (int i = 0; i < seat.length; i++) {
                    for (int j = 0; j < seat[i].length; j++) {
                        System.out.print((char) ('A' + i));
                        System.out.print(reser.SeatCheck(seat[i][j], j) + "\t");
                    }
                    System.out.println();
                }
            } else if (choice == 3) {
                for (int i = 0; i < seat.length; i++) {
                    for (int j = 0; j < seat[i].length; j++) {
                        System.out.print((char) ('A' + i));
                        System.out.print(reser.SeatCheck(seat[i][j], j) + "\t");
                    }
                    System.out.println();
                }

                System.out.print("좌석번호를 선택해주세요. >> ");
                String seatNum = sc.next();

                char[] reservationSeat = seatNum.toCharArray();

                int line = reservationSeat[0] - 'A';
                int num = reservationSeat[1] - '0';
                seat[line][num] = reservationSeat[0] + String.valueOf(reservationSeatNum);
                reservationSeatNum++;

                for (int i = 0; i < seat.length; i++) {
                    for (int j = 0; j < seat[i].length; j++) {
                        System.out.print((char) ('A' + i));
                        System.out.print(reser.SeatCheck(seat[i][j], j) + "\t");
                    }
                    System.out.println();
                }
                System.out.println("고객님의 예약번호는 " + seat[line][num] + "입니다.");
            } else if (choice == 4) {
                System.out.print("취소하실 예약번호를 입력해주세요 >> ");
                String seatNum = sc.next();

                for (int i = 0; i < seat.length; i++) {
                    for (int j = 0; j < seat[i].length; j++) {
                        if (seatNum.equals(seat[i][j])) {
                            seat[i][j] = null;
                        }
                    }
                }

                for (int i = 0; i < seat.length; i++) {
                    for (int j = 0; j < seat[i].length; j++) {
                        System.out.print((char) ('A' + i));
                        System.out.print(reser.SeatCheck(seat[i][j], j) + "\t");
                    }
                    System.out.println();
                }
            } else if (choice == 5) {
                System.out.println("프로그램 종료");
                return;
            } else {
                System.out.println("잘못된 입력");
            }
        }
    }
}

상속의 확장 - 추상메소드

[추상메소드 실습1] 인형뽑기 기계 만들기

github 인형뽑기 기계 소스코드

[추상메소드 실습2] 직원관리 프로그램 만들기

Employee라는 추상클래스에는 추상메소드인 payment()가 정의되어있다. Employee 는 추상메소드가 정의되어있기 때문에, 반드시 추상클래스이어야 한다. 추상메소드가 일반 클래스의 상속과의 관계에서 장점은, 상속은, 오버라이딩을 자식 클래스가 하든지, 하지 않든지 상관이 없다. 하지만 추상클래스를 상속받은 자식 클래스는 추상클래스에서 정의된 추상메소드를 반드시 구현해야만 한다.

추상메소드는 함수의 signature 만 정의되어 있을 뿐, 함수의 구체적인 내용(block, {}로 감싸진 부분)이 없다. 그 이유는, 추상클래스인 부모 클래스를 상속받은 자식 클래스가 반드시 구현(오버라이딩)해야 하기 때문에, 기능을 미리 정의하는게 의미가 없기 때문이다.

Employee 클래스

abstract 로 정의된 추상클래스이다. payment()라는 함수가 추상메소드로서 정의되어있다.

Employee.java

package Payment;

public abstract class Employee {
    private String number;
    private String name;
    private int pay;

    public Employee(String number, String name, int pay) {
        super();
        this.number = number;
        this.name = name;
        this.pay = pay;
    }

    public abstract double payment();

    @Override
    public String toString() {
        return number + " " + name;
    }

    public int getPay() {
        return pay;
    }

}

PartEmployee 클래스

추상클래스인 Employee를 상속받고 있다. 따라서 Employee의 추상메소드인 payment()를 반드시 구현해야 한다.
PartEmployee 는 일한 날짜에 따라 급여가 산정된다.

PartEmployee.java

package Payment;

public class PartEmployee extends Employee {
    private int day;

    public PartEmployee(String number, String name, int pay, int day) {
        super(number, name, pay);
        this.day = day;
    }

    @Override
    public double payment() {
        return (super.getPay() * day);
    }

}

RegularEmployee 클래스

추상클래스인 Employee를 상속받고 있다. 따라서 Employee의 추상메소드인 payment()를 반드시 구현해야 한다.
RegularEmployee(정규직) 는 연봉 기본급에 보너스를 더해 12개월로 나눈만큼의 급여를 지급받는다.

RegularEmployee.java

package Payment;

public class RegularEmployee extends Employee {
    private int bonus;

    public RegularEmployee(String number, String name, int pay, int bonus) {
        super(number, name, pay);
        this.bonus = bonus;
    }

    @Override
    public double payment() {
        return ((double)(super.getPay() + bonus)) / 12;
    }
}

TempEmployee 클래스

추상클래스인 Employee를 상속받고 있다. 따라서 Employee의 추상메소드인 payment()를 반드시 구현해야 한다.
TempEmployee(임시직)은 Employee 클래스의 pay에 정해진 기간만큼 나누어 급여를 지급받는다.

TempEmployee.java

package Payment;

public class TempEmployee extends Employee {
    private int period;

    public TempEmployee(String number, String name, int pay, int period) {
        super(number, name, pay);
        this.period = period;
    }

    @Override
    public double payment() {
        return ((double)super.getPay() / period);
    }
}

PaymentMain 클래스

PaymentMain.java

package Payment;

import java.util.ArrayList;

public class paymentMain {

    public static void main(String[] args) {
        ArrayList<Employee> emps = new ArrayList<Employee>();

        emps.add(new TempEmployee("E001","이은진",5000,6));
        emps.add(new RegularEmployee("E002","황한돈",3000,400));
        emps.add(new PartEmployee("E003","박방권",5,10));
        emps.add(new PartEmployee("E004","김무화",10,20));

        System.out.println("========= 9월 인건비 지급내역서 =========");

        for(int i = 0; i < emps.size(); i++) {
            printPay(emps.get(i));
        }

        System.out.println("9월 인건비 총액 : " + getMonthTotal(emps) + "만원");
    }

    private static int getMonthTotal(ArrayList<Employee> emps) {
        int allpay = 0;
        for(int i = 0; i < emps.size(); i++) {
            allpay += emps.get(i).payment();
        }
        return allpay;
    }

    private static void printPay(Employee employee) {
        double pay = cut(employee.payment());
        //String str = String.format("%.2f", pay);
        System.out.println(employee + " : " + pay + "만원");
    }

    private static double cut(double payment) {
        return ((int)(payment * 100))/100.0;
    }

}

먼저 UPCasting 이 무엇을 편하게 해주는지 이해하자. 서로 다른 클래스이지만, 동일한 클래스 타입으로 취급받을 수 있었다.
"월급산정"이라는 표면적으로는 동일한 행위가, 각 근무형태(정규직, 알바, 계약직)에 따라 구체적으로는 다르다. 이를 다형성으로 해결했다. TempEmployee, RegularEmployee, PartEmployee 는 모두 Employee 를 상속받으므로, Employee 처럼 취급될 수 있었고, Employee 의 함수인 getPayment() 를 실행할 수 있다.

추상 메소드

부모클래스의 상속을 받는 자식 클래스 속에 메소드를 강제로 가질 수 있도록 하는 지시자가 abstract 있다.

이 때 생겨나는 부모 클래스의 메소드 중에 {} 내부의 내용이 없고 abstract 지시자가 붙은 메소드를 '추상메소드'라고 부른다. 또한, 추상 메소드를 하나 이상 포함하고 있는 클래스를 '추상클래스'라고 한다. 따라서 클래스에게도 추상메소드를 가지고 있다는 의미로, abstract 를 명시해줘야 한다(그렇지 않으면 컴파일 에러가 발생한다.).

이 부모 클래스를 상속받는 자식 클래스에서 부모의 메소드를 사용하지 않으면 다음과 같은 오류가 나타난다.

The type Mang must implement the inherited abstract method Doll.print()  

implement: 도입하다.시행하다. (특히 프로그래밍에서) 구현하다.
cannot instantitate: 추상메소드는 인스턴스화(객체화)가 불가능하다.

IDE 의 기능을 활용하여, 특정 메소드가 오버라이딩한 메소드라는 사실을 알 수 있다. Eclipse 에서는 toString() 메소드 선언시 왼쪽에 표시가 생기는데 이것은 오버라이딩을 했다는 뜻이 된다. (마우스를 가져다 대면 어디의 것을 오버라이딩 했는지 를 알 수 있다.)

IntelliJ에서는 라인넘버 옆에 빨강색 화살표로 overriding을 하고 있는 메소드를, 회색 화살표로 오버라이딩을 하게 하고 있음을 보여준다.

toString() 과 overriding

toString()은 원래 Object 클래스의 것인데, 이 toString() 의 기능은 해당 객체의 주소값을 반환하는 역할을 해준다. 그러나 오버라이딩 해주게 되면 해당 클래스의 프로그래머가 직접 구현해준 toString() 메소드의 리턴값을 반환하게 된다.

결국에 기능단위로 쪼갠다는 것은 유지보수를 용이하게 하기 위함이다.

어노테이션(애노테이션, annotation)이란?
annotation
@Override는 오버라이딩 되었다는 것을 표시해주기 위한 기호이다.
(생략은 가능하지만, 그러나 오버라이딩 되지 않은 곳에 이 기호를 썼을 때에는 오류가 발생한다.)

반응형

Designed by JB FACTORY