본문 바로가기

BackEnd/Java

1012 JAVA - Interface 인터페이스 - 문제

728x90
반응형

Contents

     

    인터페이스의 필요성


    구현의 강제로 코드의 통일성 향상(= 표준화)


    인터페이스를 통한 간접적인 클래스 사용으로 모듈 교체가 용이
      => 부모 인터페이스 타입으로 클래스를 다루게 되면 실제 인스턴스가 바뀌더라도 기존 코드를 수정할 필요가 없어짐
    서로 상속 관계가 없는 클래스간의 인터페이스를 통한 상속 관계 부여
       => 다형성 확장
     모듈간 독립적 프로그래밍으로 인한 개발 기간 단축

     

     인터페이스를 통한 간접적인 클래스 사용으로 모듈 교체가 용이  => 인터페이스 사용 시 손쉬운 모듈 교체를 지원한다!

     

     

     

     

    문제 1


    		PrinterClient pc = new PrinterClient();
    		
    		// PrinterClient 인스턴스의 setPrinter() 메서드를 호출하여
    		// 각 프린터기 인스턴스를 파라미터로 전달하면 업캐스팅 일어남
            
    		pc.setPrinter(new LaserPrinter()); // LaserPrinter -> Printer 업캐스팅
    		// => setPrinter(Printer printer)로 정의되어 있으므로
    		//    Printer printer = new LaserPrint(); 가 됨
    		//    좌변의 타입이 부모클래스 타입이고, 오른쪽의 인스턴스 생성이 자식클래스이라면
    		//    묵시적 형변환 즉, 업캐스팅이 일어남!
            
    		pc.print("Hello.java");
    		// => PrinterClient 인스턴스의 print() 메서드를 호출하면
    		//    인스턴스 내의 Printer 타입 변수에 저장된 인스턴스의 print() 호출됨
    		//    => 결국 실제 저장된 LaserPrinter 인스턴스의 print() 메서드가 호출됨
    		
    		// 현재 LaserPrinter 를 InkjetPrinter 로 교체 시
    		// setPrinter() 메서드에 InkjetPrinter 인스턴스만 전달하면
    		// 자동으로 출력 대상이 변경됨
            
    		pc.setPrinter(new InkjetPrinter()); // InkjetPrinter -> Printer 업캐스팅
    		pc.print("Hello.java");
    		
    		pc.setPrinter(new DotPrinter()); // DotPrinter -> Printer 업캐스팅
    		pc.print("Ex3.java");
    		
    	}
    
    }
    
    // 각 프린터를 직접 다루지 않고 상위 타입인 Printer 인터페이스를 다루는
    // PrinterClient 클래스 정의
    class PrinterClient {
    	// 각각의 프린터 클래스를 다루기 위한 슈퍼클래스 타입에 해당하는
    	// Printer 인터페이스 타입 변수 선언
    	private Printer printer;
    
    	// Setter 메서드를 통한 Printer 타입 변수 초기화
    	public void setPrinter(Printer printer) {
    		this.printer = printer;
    	}
    	
    	// 외부로부터 출력할 파일을 전달받아 실제 프린터에 해당하는 각 인스턴스의 
    	// print() 메서드를 호출한 뒤 파일을 전달하여 출력 작업을 수행
    	public void print(String fileName) {
    		// Printer 타입 변수에 저장된 각 프린터의 인스턴스를 통해
    		// print() 메서드를 호출하면 해당 프린터의 출력 기능을 사용 가능함
    		printer.print(fileName);
    	}
    }
    
    // --------------------------------------------------------------------
    /*
     * 문서 등을 프린터로 출력하기 위한 각 프린터 클래스 정의
     * => 각 프린터의 출력 기능을 갖는 printer 인터페이스를 정의하고
     *    각 프린터 클래스에서 상속받아 구현
     */
    
    interface Printer { // 프린터
    	// 프린터기의 공통 기능인 출력(print()) 기능을 추상메서드 정의
    	public abstract void print(String fileName);
    }
    
    class LaserPrinter implements Printer { // 레이저 프린터
     
    	// 파일(String 타입 fileName) 을 전달받아 출력 작업을 수행하는 print() 메서드 정의
    	// => Printer 인터페이스로부터 상속받아 구현
    	@Override
    	public void print(String fileName) {
    		System.out.println("Laser Printer 로 " + fileName + " 출력하기!");
    	}
    }
    
    class InkjetPrinter implements Printer { // 잉크젯 프린터
    	
    	@Override
    	public void print(String fileName) {
    		System.out.println("Inkjet Printer 로 " + fileName + " 출력하기!");
    	}
    }
    
    class DotPrinter implements Printer { // 도트 프린터
    	
    	@Override
    	public void print(String fileName) {
    		System.out.println("Dot Printer 로 " + fileName + " 출력하기!");
    	}
    }

     

    문제2


    package interface_;
    
    public class Ex4 {
    
    	public static void main(String[] args) {
    		// 3. 서로 상속 관계가 없는 클래스간에 인터페이스를 통한 상속 관계 부여
    		// => 다형성 확장
    		
    		Ex4 ex = new Ex4();
    		ex.noRelationShip();
    		System.out.println("---------------");
    		ex.hasRelationShip();
    
    		
    		
    	} // main() 메서드 끝
    	
    	public void noRelationShip() {
    //		NoteBookPc notebook = new NoteBookPc();
    //		notebook.charge();
    //		SmartPhone smartPhone = new SmartPhone();
    //		smartPhone.charge();
    		
    		// 두 개의 인스턴스를 하나의 배열로 관리해야 할 경우
    		// NoteBookPc 와 SmartPhone 의 공통 타입은 Object 타입밖에 없음
    		Object[] objArr = {new NoteBookPc(), new SmartPhone()};
    		
    		// 반복문을 사용하여 배열 크기만큼 반복
    		for(int i = 0; i < objArr.length; i++) {
    //			objArr[i].charge();
    			// => 참조 영역 축소로 인해 Object 타입으로 charge() 메서드 호출 불가!
    			
    			// instanceof 연산자를 사용하여 NoteBookPc 와 SmartPhone 타입 판별
    			// => 다운캐스팅을 통해 각 인스턴스를 따로 접근해야 함!
    			//    접근하고자 하는 charge() 메서드는 각 클래스에서 직접 정의한
    			//    인스턴스 멤버 메서드이기 때문!
    			if(objArr[i] instanceof NoteBookPc) {
    				// Object -> NoteBookPc 타입으로 다운캐스팅 후 charge() 호출
    				NoteBookPc notebook = (NoteBookPc)objArr[i];
    				notebook.charge(); // 노트북의 충전기를 통해 충전
    			} else if(objArr[i] instanceof SmartPhone) {
    				// Object -> SmartPhone 타읍으로 다운캐스팅 후 charge() 호출
    				SmartPhone smartPhone = (SmartPhone)objArr[i];
    				smartPhone.charge(); // 스마트폰의 충전기를 통해 춘전
    			}
    			
    		}
    		
    	}
    	
    	
    	public void hasRelationShip() {
    		// 인터페이스를 사용하여 공통된 멤버를 갖는 상속 관계를 부여할 경우
    		// 해당 인터페이스 타입으로 다운캐스팅 할 필요없이
    		// 업캐스팅 된 상태 그대로 멤버에 접근 가능
    		// => 다형성으로 인한 코드 절약
    		Chargeable c = new NoteBookPc2(); // NoteBookPc2 -> Chargeable 
    		Chargeable c2 = new SmartPhone2(); // SmartPhone2 -> Chargeable
    		
    		// Chargeable 타입 배열로 두 클래스 인스턴스 모두 관리 가능(업캐스팅)
    		Chargeable[] chageableArr = {new NoteBookPc2(), new SmartPhone2()};
    		
    		// 업캐스팅 후에도 공통 메서드 charge() 를 호출 가능하므로
    		// 별도의 다운캐스팅 없이 바로 charge() 메서드 접근 가능
    		for(int i = 0; i < chageableArr.length; i++) {
    			chageableArr[i].charge();
    			
    		}
    		
    		
    	}
    
    } // Ex4 클래스 끝
    
    // Object 클래스 외에 슈퍼클래스가 없는 NoteBookPc 와 SmartPhone 의
    // 공통 인터페이스 Chargeable 인터페이스 정의
    interface Chargeable {
    	// 두 클래스에서 공통으로 사용할 충전(charge()) 기능을 추상메서드로 정의
    	public abstract void charge();
    }
    
    // 기존에 Pc 클래스를 상속받고 있는 상태에서 
    // 추가로 인터페이스를 구현해야하는 경우 상속 코드 뒤에 구현 코드를 기술
    // => implements Chargeable 코드 추가
    // => 아무 관계도 없던 두 클래스에 동일한 부모 인터페이스가 추가되어
    //    서로 상속 관계로 묶이게 됨
    class NoteBookPc2 extends Pc implements Chargeable {
    	@Override
    	public void charge() {
    		System.out.println("노트북 충전 중...");
    	}
    }
    
    class SmartPhone2 extends HandPhone implements Chargeable {
    	@Override
    	public void charge() {
    		System.out.println("스마트폰 충전 중...");
    	}
    }
    
    
    // ===============================================================
    class Pc {}
    
    class NoteBookPc extends Pc {
    	public void charge() {
    		System.out.println("노트북 충전 중...");
    	}
    }
    
    class HandPhone {}
    
    class SmartPhone extends HandPhone {
    	public void charge() {
    		System.out.println("스마트폰 충전 중...");
    	}
    }

     

     

    문제3


    package interface_;
    
    public class Ex5 {
    
    	public static void main(String[] args) {
    		// 4. 모듈간 독립적 프로그래밍으로 인한 개발 기간 단축
    		DesignerClient desinger = new DesignerClient();
    		desinger.login();
    		
    		System.out.println("-------------------");
    		
    		DeveloperClient developer = new DeveloperClient();
    		developer.login();
    
    	}
    
    }
    
    // 개발자와 디자이너 사이의 규칙을 인터페이스로 정의
    interface LoginProcess {
    	// 공통 기능으로 login() 메서드를 정의하여 파라미터와 리턴타입 지정
    	public abstract String login(String id, String pass);
    }
    
    // 디자이너의 경우
    // => 로그인 처리 과정은 중요하지 않고 전달 데이터와 리턴 데이터만 중요함
    // => LoginProcess 인터페이스를 구현하는 클래스를 정의하여
    //    login() 메서드 구현
    class Designer implements LoginProcess {
    
    	@Override
    	public String login(String id, String pass) {
    		// 메서드에 전달되는 데이터가 정확한지만 확인하고
    		// 리턴값이 외부로 잘 전달되는지만 확인하면 된다!
    		System.out.println("디자이너가 전달받은 아이디 : " + id);
    		System.out.println("디자이너가 전달받은 패스워드 : " + pass);
    		return "성공";
    	}
    }
    
    class DesignerClient { // 디자이너
    	Designer designer = new Designer();
    	
    	public void login() {
    		String id = "admin";
    		String pass = "1234";
    		// login() 메서드를 호출하여 파라미터로 아이디, 패스워드를 전달하고
    		// 로그인 결과로 리턴되는 값을 출력하여 확인 작업 수행
    		String result = designer.login(id, pass);
    		System.out.println("로그인 결과 : " + result);
    		
    		if(result.equals("성공")) {
    			// 로그인 성공 페이지로 이동 처리 작업 수행
    		} else {
    			// 로그인 실패 페이지로 이동 처리 작업 수행
    		}
    		
    	}
    }
    
    // 개발자의 경우
    // => 전달받은 값은 중요하지 않고 전달받은 값을 사용하여 로그인 처리 작업 수행
    //    로그인 처리 후 리턴되는 값이 정상적으로 전달되는지만 확인
    // => LoginProcess 인터페이스를 구현하는 Develper 클래스 정의
    
    class Developer implements LoginProcess {
    	
    	// 추상 메서드 구현 필수!
    	@Override
    	public String login(String id, String pass) {
    		// 디자이너로부터 전달받은 아이디와 패스워를 사용하여
    		// 로그인 작업을 처리한 후 "성공" 또는 "실패" 문자열 리턴
    		System.out.println("개발자가 전달받은 아이디 : " + id);
    		System.out.println("개발자가 전달받은 패스워드 : " + pass);
    		
    		System.out.println("아이디와 패스워드로 로그인 작업 처리 완료!");
    		return "성공";
    	}
    }
    
    class DeveloperClient {
    	Developer developer = new Developer();
    	
    	public void login() {
    		// 디자이너가 전달하게 될 아이디와 패스워드를 임의로 설정하여 전달하고
    		// 개발자 코드를 통해 로그인 작업을 수행한 후
    		// 리턴되어지는 값이 정상적인지만 확인하면 된다
    		String result = developer.login("admin", "1234");
    		System.out.println("로그인 결과 : " + result);
    	}
    }

     

     

    문제4


    package interface_;
    
    public class Test5 {
    
    	public static void main(String[] args) {
    		Photoshop p = new Photoshop();
    		
    		p.draw(new Circle()); // Shape s = new Circle() 과 동일
    		p.draw(new Rectangle()); // Shape s = new Rectangle() 과 동일
    
    	}
    
    }
    
    // ------------------------------------------------------
    // 모든 도형의 그리기 기능을 제공하는 Shape 인터페이스 정의
    // => draw() 추상메서드 정의(리턴값 없음, 파라미터 없음)
    interface Shape {
    	public abstract void draw();
    }
    
    // Shape 인터페이스를 구현하는 Circle, Retangle 클래스 정의
    // => 추상메서드 draw() 를 오버라이딩하여 각자 도형 그리기 기능을 구현
    //    ex) Circle 은 "원 그리기!", Rectangle 은 "사각형 그리기!" 출력
    // => Circle : 멤버변수(반지름, radius, 실수형, 접근제한자: private)
    //             Setter() 메서드, draw() 메서드("원그리기! 반지름 : 반지름길이")  
    
    // => Rectangle : 멤버변수(가로, width, 실수형, 접근제한자 : private
    //						  (세로, height, 실수형, 접근제한자 : private)
    // => Rectangle : Setter() 메서드, draw() 메서드
    //                                 (가로 : 가로길이, 세로 : 세로길이 의 사각형 그리기!)
    
    class Circle implements Shape {
    	private double radius = 3.0;
    
    	public void setRadius(double radius) {
    		this.radius = radius;
    	}
    
    	@Override
    	public void draw() {
    		System.out.println("원 그리기! - 반지름 : " + radius);	
    	}
    }
    
    class Rectangle implements Shape {
    	private double width = 2.0;
    	private double height = 1.5;
    	
    	public void setWidth(double width) {
    		this.width = width;
    	}
    	public void setHeight(double height) {
    		this.height = height;
    	}
    	@Override
    	public void draw() {
    		System.out.println("가로 : " + width + ", 세로 : " + height + " 의 사각형 그리기!");
    	}
    }
    
    class Photoshop {
    	// draw() 메서드 정의
    	// => Circle, Rectangle 인스턴스를 전달받아 해당 인스턴스의 draw() 호출
    	//    두 인스턴스의 공통 타입으로 Shape 인터페이스를 파라미터 타입으로 지정
    	public void draw(Shape s) { // Circle&Rectangle -> Shape 업캐스팅
    		// Shape 타입 변수의 draw() 메서드 호출 시 실제 인스턴스의 draw() 호출됨
    		s.draw();	
    	}
    }
    728x90
    반응형