웹_프론트_백엔드/단과

[단과_JAVA] 2020.02.25

shine94 2020. 2. 26. 12:38

<드디어 최종 완성!!>

** Bus 클래스 **

package transportation;

import java.util.Random;

import javax.swing.JOptionPane;

public class Bus implements TransportationMark{
	// private 필드는 다른 클래스에서 접근할 수 없으므로
	// public getter와 setter를 만들어 주어야 한다.
	// 따라서 외부에서 private필드에 접근하기 위해서는
	// getter, setter를 사용하거나 생성자로 접근한다.
	private String[] stops;
	private String num;

	public final int FEE = 1250;

	public int depart_idx;

	public Bus() {
	}

	public Bus(String[] stops, String num) {
		//외부에서 전달된 정류소가 5군데가 아닐 시 막아준다.
		if (stops.length == 5) {
			this.stops = stops;
		} else {
			JOptionPane.showMessageDialog(null, "정류장은 5개입니다.");
			//강제 종료
			System.exit(0);
		}
		this.num = num;
	}

	public String[] getStops() {
		return stops;
	}

	public void setStops(String[] stops) {
		if (stops.length == 5) {
			this.stops = stops;
		} else {
			JOptionPane.showMessageDialog(null, "정류장은 5개입니다.");
			System.exit(0);
		}
	}

	public String getNum() {
		return num;
	}

	public void setNum(String num) {
		this.num = num;
	}

	//출발지를 랜덤하게 조정
	public void start() {
		Random r = new Random();
		depart_idx = r.nextInt(stops.length - 1);
	}

	//다른 지역에 있는 money를 수정해야 하므로
	//값이 아닌 주소로 전달받는다.
	//사용자가 선택한 도착지 번호도 전달받는다.
	public int go(int[] money, int dest_idx) {
		//Flag
		int check = -1;

		if (dest_idx - depart_idx <= 0) {
			// 역방향 혹은 현재 위치한 정류소 선택(잘못 선택)
			check = 0;
		} else {
			//사용자 돈을 pay메소드에서 검사
			//잔액부족시 false
			if (pay(money)) {
				int i = 0;
				//출발지 인덱스부터 도착지 전 정류장까지 반복하여 출력
				for (i = depart_idx; i < dest_idx; i++) {
					System.out.print(stops[i] + " > ");
					try {Thread.sleep(1000);} catch (InterruptedException e) {;}
				}
				//마지막 도착지 출력
				System.out.println(stops[i] + " > 도착");
				//정상 운행
				check = 1;
			}
		}
		// -1 : 잔액부족, 0 : 잘못선택, 1 : 정상
		return check;
	}

	public boolean pay(int[] money) {
		boolean check = false;
		//잔액이 부족하지 않으면 차감 후 잔고 출력
		if (money[0] - FEE >= 0) {
			money[0] -= FEE;
			JOptionPane.showMessageDialog(null, "남은 잔액 : " + money[0] + "원");
			check = true;
		}
		return check;
	}
}


** Subway 클래스 **

package transportation;

import java.util.Random;

import javax.swing.JOptionPane;

public class Subway implements TransportationMark{
	private String[] stops;
	private String num;

	public final int FEE = 1250;

	public int depart_idx;

	public Subway() {
	}

	public Subway(String[] stops, String num) {
		if (stops.length == 7) {
			this.stops = stops;
		} else {
			JOptionPane.showMessageDialog(null, "정류장은 7개입니다.");
			System.exit(0);
		}
		this.num = num;
	}

	public String[] getStops() {
		return stops;
	}

	public void setStops(String[] stops) {
		if (stops.length == 7) {
			this.stops = stops;
		} else {
			JOptionPane.showMessageDialog(null, "정류장은 7개입니다.");
			System.exit(0);
		}
	}

	public String getNum() {
		return num;
	}

	public void setNum(String num) {
		this.num = num;
	}

	public void start() {
		Random r = new Random();
		depart_idx = r.nextInt(stops.length);
	}

	public int go(int[] money, int dest_idx) {
		int check = -1;

		if (dest_idx - depart_idx == 0) {
			// 현재 위치한 정류소 선택(잘못 선택)
			check = 0;
		} else if(dest_idx - depart_idx > 0) {
			//정방향
			if (pay(money)) {
				int i = 0;
				for (i = depart_idx; i < dest_idx; i++) {
					System.out.print(stops[i] + " > ");
					try {Thread.sleep(2000);} catch (InterruptedException e) {;}
				}
				System.out.println(stops[i] + " > 도착");
				check = 1;
			}
		}else {
			//역방향
			if (pay(money)) {
				int i = 0;
				//출발지 인덱스가 더 크기 때문에
				//도착지까지 가기 위해서는 1씩 감소를 해야한다.
				for (i = depart_idx; i > dest_idx; i--) {
					System.out.print(stops[i] + " > ");
					try {Thread.sleep(2000);} catch (InterruptedException e) {;}
				}
				System.out.println(stops[i] + " > 도착");
				check = 1;
			}
		}
		// -1 : 잔액부족, 0 : 잘못선택, 1 : 정상
		return check;
	}

	public boolean pay(int[] money) {
		boolean check = false;
		if (money[0] - FEE >= 0) {
			money[0] -= FEE;
			JOptionPane.showMessageDialog(null, "남은 잔액 : " + money[0] + "원");
			check = true;
		}
		return check;
	}
}


** Taxi 클래스 **

package transportation;

import java.util.Random;

public class Taxi implements TransportationMark{
	//기본 요금
	final int FEE = 3800;
	
	//km당 요금
	final int PER_KM = 1200;

	private String name;
	
	public Taxi() {}
	
	public Taxi(String name) {
		super();
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public void go(int[] money, String destination) {
		Random r = new Random();
		// 1~10km
		// 0~9 + 1
		//랜덤한 km
		int km = r.nextInt(10) + 1;
		
		//마지막 1km는 금액이 정산되지 않기 때문에(pay()를 사용하지 않는다)
		//미리 total에 적용시킨다.
		int total = FEE + PER_KM;
		System.out.print(destination + "까지의 남은 거리 : ");

		int i;
		for (i = km; i > 1; i--) {
			//km당 1200원을 total에 누적
			total += PER_KM;
			System.out.print(i + "km > ");
			try {Thread.sleep(500);} catch (InterruptedException e) {;}
		}
		System.out.println(i + "km > 도착");

		//도착 후 잔액검사
		if (!pay(money, total)) {
			//잔액부족시 돈을 0원으로 만들고 메세지 출력
			money[0] = 0;
			System.out.println("잔액부족 / 경찰 출동중");
		}
		System.out.println("남은 잔고 : " + money[0] + "원");
	}

	public boolean pay(int[] money, int total) {
		boolean check = false;
		if (money[0] - total >= 0) {
			check = true;
			money[0] -= total;
		}
		return check;
	}
}


** Stop 메인메소드 클래스 **

package transportation;

import java.util.Scanner;

public class Stop {
	public static void main(String[] args) {
		/*버스*/
		String[] stops_41 = {"강남", "역삼", "선릉", "삼성", "종합운동장"};
		String[] stops_141 = {"연신내", "녹번", "대조동", "박달고개", "역촌사거리"};
		String[] stops_1001 = {"일산서부경찰서", "대화역", "주엽고교", "후곡마을", "행정복지센터"};
		
		/*전철*/
		String[] stops_line2 = {"서초", "방배", "사당", "낙성대", "서울대입구", "봉천", "신림"};
		String[] stops_line3 = {"남부터미널", "교대" , "고속터미널", "잠원", "신사", "압구정", "옥수"};
		
		/*버스 배열*/
		Bus[] buses = {
				new Bus(stops_41, "41"),
				new Bus(stops_141, "141"),
				new Bus(stops_1001, "1001")
		}; 
		/*전철 배열*/
		Subway[] lines = {
				new Subway(stops_line2, "2"),
				new Subway(stops_line3, "3")
		};
		
		/*택시 배열*/
		Taxi[] taxies = {
			new Taxi("카카오 택시")
		};
		
		//up casting
		TransportationMark[][] trans = {buses, lines, taxies};
		Scanner sc = new Scanner(System.in);
		
		//대중교통 인덱스
		int row_choice = 0;
		//사용자가 선택한 대중교통의 종류
		int column_choice = 0;
		
		int[] money = {10000};
		int dest_idx = 0;
		
		while(true) {
			System.out.println("[대중교통]\n1.버스\n2.지하철\n3.택시\n4.나가기");
			row_choice = sc.nextInt();
			sc.nextLine();
			
			if(row_choice == 4) {break;}
			
			row_choice--;
			while(true) {
				int i;
				//사용자가 선택한 대중교통 메뉴 출력
				for (i = 0; i < trans[row_choice].length; i++) {
					if(row_choice == 0) {
						System.out.println(i+1+"."+((Bus)trans[row_choice][i]).getNum());
					}else if(row_choice == 1) {
						System.out.println(i+1+"."+((Subway)trans[row_choice][i]).getNum());
					}else {
						System.out.println(i+1+"."+((Taxi)trans[row_choice][i]).getName());
					}
				}
				System.out.println(i+1+".대중교통 다시 선택");
				column_choice = sc.nextInt();
				sc.nextLine();
				
				if(column_choice == i+1) {break;}
				
				column_choice--;
				
				int temp = 0;
				
				//사용자가 선택한 대중교통이 버스일 때
				if(trans[row_choice][column_choice] instanceof Bus) {
					//down casting
					//버스 필드에 접근하고자 할 때 up casting된 객체를 반드시
					//down casting해야한다.
					Bus bus = (Bus)trans[row_choice][column_choice];
					bus.start();
					
					//정류소를 출력하는 영역
					for (i = 0; i < bus.getStops().length; i++) {
						System.out.print(i+1+bus.getStops()[i] + " ");
					}
					//출발지를 출력하는 영역
					System.out.println("\n출발지 : " + bus.getStops()[bus.depart_idx]);
					
					dest_idx = sc.nextInt()-1;
					
					//temp는 결과값을 담고 있다(-1, 0, 1)
					temp = bus.go(money, dest_idx);
					
					
				//사용자가 선택한 대중교통이 전철일 때
				}else if(trans[row_choice][column_choice] instanceof Subway) {
					Subway subway = (Subway)trans[row_choice][column_choice];
					subway.start();
					for (i = 0; i < subway.getStops().length; i++) {
						System.out.print(i+1+subway.getStops()[i] + " ");
					}
					System.out.println("\n출발지 : " + subway.getStops()[subway.depart_idx]);
					dest_idx = sc.nextInt()-1;
					temp = subway.go(money, dest_idx);
					
				//사용자가 선택한 대중교통이 택시일 때
				}else {
					Taxi taxi = (Taxi)trans[row_choice][column_choice];
					System.out.print("도착지 : ");
					taxi.go(money, sc.nextLine());
				}
				
			}
			
		}
		
		//1.대중교통을 선택(버스, 지하철, 택시 중 택 1)
		//2.버스와 지하철은 어떤 것인지도 선택(41, 141, .... 중 택 1)
		//1.과 2.에서 입력받은 정수가 각각 행과 열에 들어간다.
		//택시일 경우 Flag를 사용해서 가려내고 go()만 사용해준다.
		
		
////		String[] stops = {"서초", "교대", "강남", "역삼", "선릉"};
////		String[] stops = {"서초", "교대", "강남", "역삼", "선릉", "삼성", "종합운동장"};
//		int[] money = {10000};
//		Taxi kakao = new Taxi("카카오택시");
////		Bus bus_41 = new Bus(stops, "41");
////		Subway line2 = new Subway(stops, "2");
//		Scanner sc = new Scanner(System.in);
//		System.out.print("도착지 : ");
//		
//		kakao.go(money, sc.nextLine());
//		
////		bus_41.start();
//		
////		line2.start();
////		for (int i = 0; i < bus_41.getStops().length; i++) {
////			System.out.print(i+1+bus_41.getStops()[i] + " ");
////		}
////		for (int i = 0; i < line2.getStops().length; i++) {
////			System.out.print(i+1+line2.getStops()[i] + " ");
////		}
////		System.out.println("\n출발지 : " + bus_41.getStops()[bus_41.depart_idx]);
////		System.out.println("\n출발지 : " + line2.getStops()[line2.depart_idx]);
////		System.out.println("도착할 정류소 번호를 입력하세요.");
////		if(bus_41.go(money, sc.nextInt()-1) != 1) {
////		if(line2.go(money, sc.nextInt()-1) != 1) {
////			System.out.println("다음 버스를 이용해주세요.");
////		}
	}
}


** TransportationMark 인터페이스 **

package transportation;
//공통 타입이 없는 클래스들을 그룹화 하기 위한 목적
public interface TransportationMark {;}

 

1. 내부 클래스(inner class)
 : 클래스 내부에 클래스를 선언하여 외부 클래스의 필드 접근에
   용이하기 하기 위함.
   내부 클래스의 필드를 사용하기 위해서는 외부 클래스 객체로
   내부 클래스를 객체화 해야한다.
   
   외부클래스명 외부객체명 = new 외부생성자();
   외부클래스명.내부클래스명 내부객체명 = 외부객체명.new 내부생성자();

 


2. 내부 클래스를 사용하는 이유

 : A클래스에서 b라는 작업이 자주 쓰이고, 이 작업은 B클래스를 만들어야
   쉽게 관리할 수 있다. 하지만 다른 클래스에서는 b작업이 필요 없거나
   외부에 노출시키고 싶지 않을 때 사용한다. 이것을 캡슐화라고 한다.
   
   내부 클래스는 GUI(Graphic User Interface) 개발시 많이 사용된다.
   예를 들어 하나의 클래스에 a라는 버튼과 b라는 버튼의 기능을 구현할 때
   각각 클래스로 분리해서 만드는 것보다 내부 클래스로 만들어 사용하는 것이 적합!


3. 익명클래스 (Anonymous inner class)
 : 이름은 없고 중괄호 영역만 존재한다.
   일회성이기 때문에 이름이 없어도 무방하다.
   하지만 메모리에 할당은 된다.

 

 

4. 오늘 실습코드

1) 내부클래스, 익명클래스 예제

** Cafe 인터페이스 **

package inner;

public interface Cafe {
	String[] getMenu();
	void setMenu(String[] menu);
	void sell(String choice);
}


** 인터페이스 Cafe를 인터페이스 받은 CafeAdapter 추상 클래스**

package inner;

public abstract class CafeAdapter implements Cafe{
	@Override
	public String[] getMenu() {return null;}
	@Override
	public void setMenu(String[] menu) {}
	@Override
	public void sell(String choice) {}
}


** Road 메인 메소드 클래스 **

package inner;

public class Road {
	public static void main(String[] args) {
		StarBucks gangnam = new StarBucks();
		StarBucks jamsil = new StarBucks();
		
		jamsil.regist(new CafeAdapter() {
			@Override
			public void setMenu(String[] menu) {
				// TODO Auto-generated method stub
				super.setMenu(menu);
			}
			
			@Override
			public String[] getMenu() {
				// TODO Auto-generated method stub
				return super.getMenu();
			}
			
		});
		
		gangnam.regist(new Cafe() {
			
			String[] menu = {"아메리카노", "카페라떼", "샌드위치"};
			
			@Override
			public void setMenu(String[] menu) {
				this.menu = menu;
			}
			
			@Override
			public void sell(String choice) {
				for (int i = 0; i < menu.length; i++) {
					if(menu[i].equals(choice)) {
						System.out.println(menu[i] + "주문 완료");
					}
				}
			}
			
			@Override
			public String[] getMenu() {
				return menu;
			}
		});
	}
}

 

2) 익명클래스 예제

** InnerTest 클래스 **

package inner;

class Out{
	
	int outData;
	
	public Out() {
		System.out.println("외부 생성자 호출");
	}
	
	public void printOutData() {
		System.out.println(outData);
	}
	
	public class In{
		int inData;
		public In() {
			outData = 100;
			System.out.println("내부 생성자 호출");
		}
		
		public void printData() {
			printOutData();
			System.out.println(inData);
		}
	}
}

public class InnerTest {
	public static void main(String[] args) {
		Out out = new Out();
		Out.In in = out.new In();
		
		in.inData = 600;
		in.printData();
		
		
	}
}

 

3) 내부클래스, 추상클래스가 사용되는 예제

** WindowTest 클래스 **

package inner;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JButton;
import javax.swing.JFrame;

public class WindowTest {
	public static void main(String[] args) {
		JFrame window = new JFrame();
		JButton btn = new JButton("눌러줘요");
		
		window.setSize(500, 600);
		
		Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
		int x = (d.width - window.getWidth()) / 2;
		int y = (d.height - window.getHeight()) / 2;
		
		window.setLocation(x, y);
		
		btn.addMouseListener(new MouseAdapter() {
			@Override
			public void mousePressed(MouseEvent e) {
				System.out.println("눌렸엉");
			}
		});
		window.add(btn);
		
		window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		window.getContentPane().setBackground(Color.ORANGE);
		window.setVisible(true);
		
	}
}

'웹_프론트_백엔드 > 단과' 카테고리의 다른 글

[단과_C] 2020.02.26  (0) 2020.02.27
[단과_C] 2020.02.25  (0) 2020.02.26
[단과_C] 2020.02.24  (0) 2020.02.25
[단과_JAVA] 2020.02.24  (0) 2020.02.25
[단과_C] 2020.02.21  (0) 2020.02.22