[JAVA] 객체 지향 핵심 - 인터페이스

WOOK JONG KIM·2022년 9월 3일
0

패캠_java&Spring

목록 보기
8/103
post-thumbnail

인터페이스

  • 클래스나 프로그램이 제공하는 기능을 명시적으로 선언
  • 일종의 클라이언트 코드와의 약속이며 클래스나 프로그램이 제공하는 명세(specification)
  • 클라이언트 프로그램은 인터페이스에 선언된 메서드 명세만 보고 이를 구현한 클래스를 사용할 수 있음
  • 어떤 객체가 하나의 인터페이스 타입이라는 것은 그 인터페이스가 제공하는 모든 메서드를 구현했다는 의미임
  • 인터페이스를 구현한 다양한 객체를 사용함 - 다형성

인터페이스 구성 요소

  • 상수
  • 추상 메서드
  • 디폴트 메서드
  • 정적 메서드
package ch14;

public interface Calc {
	
	// 모든 변수는 상수로 변환됨 public static final
	double PI = 3.14;
	int ERROR = -99999999;
	
	// 선언된 모든 메서드는 추상 메서드 public abstract 
	
	int add(int num1, int num2);
	int subtract(int num1, int num2);
	int times(int num1, int num2);
	int divide(int num1, int num2);
	
	// 디폴트 메서드
	// 구현을 가지는 메서드, 인터페이스를 구현하는 클래스들에서 공통으로 사용할 수 있는 기본 메서드
	// 구현 하는 클래스에서 재정의 가능함!
	default void description() {
		System.out.println("정수의 사칙연산을 제공합니다.");
		// 인터페이스 내 사용!
		myMethod() ;
	}
	// 정적 메서드
	// 인스턴스 생성과 상관없이 인터페이스 타입으로 사용할 수 있는 메서드
	static int total(int[] arr) {
		
		int total = 0;
		for(int num:arr) {
			total += num;
		}
		myStaticMethod();
		return total;
	}
// private 메서드
//	인터페이스를 구현한 클래스에서 사용하거나 재정의 할 수 없음
//	인터페이스 내부에서만 사용하기 위해 구현하는 메서드
	private void myMethod() {
		System.out.println("myMethod");
	}
	
	private static void myStaticMethod() {
		System.out.println("myStaticMethod");
	}
}

Calculator와 CompleteCalc에서 인터페이스 구현

// Calculator.java
package ch14;

public abstract class Calculator implements Calc {

	@Override
	public int add(int num1, int num2) {
		return num1 + num2;
	}

	@Override
	public int subtract(int num1, int num2) {
		return num1 - num2;
	}

}
//CompleteCalc.java
package ch14;

public class CompleteCalc extends Calculator {

	@Override
	public int times(int num1, int num2) {
		return num1 * num2;
	}

	@Override
	public int divide(int num1, int num2) {
		if(num2 == 0)
			return ERROR;
		
		return num1/num2;
	}
	
	public void showInfo() {
		
		System.out.println("모두 구현했습니다.");
	}

	@Override
    //여기서 오버라이드 하지 않았을 시 인터페이스의 디폴트 디스크립션 함수가 호출됨
	public void description() {
		System.out.println("CompleteCalc overriding");
	}
	
	
}
package ch14;

public class CalculatorTest {

	public static void main(String[] args) {
		
		int num1 = 10;
		int num2 = 2;
		
		CompleteCalc calc = new CompleteCalc();
		System.out.println(calc.add(num1, num2));
		System.out.println(calc.subtract(num1, num2));
		System.out.println(calc.times(num1, num2));
		System.out.println(calc.divide(num1, num2));
		
		calc.description();
		
		// 인터페이스 .static 메서드 명 만으로 호출가능한 것 확인!
		int [] arr = {1,2,3,4,5};
		System.out.println(Calc.total(arr));
	}

}

인터페이스를 활용한 dao 구현하기(이해해보자..)

DAO(Data Acess Object)는 데이터베이스에 접근하여 데이터를 생성, 조회, 수정 삭제하는 역할을 담당

하나의 인터페이스를 여러 객체가 구현하게 되면 클라이언트 프로그램은 인터페이스의 메서드를 활용하여 여러 객체의 구현을 사용할 수 있음 (다형성)

DB에 회원 정보를 넣는 dao(data access object)를 여러 DB 제품이 지원될 수 있게 구현함

환경파일(db.properties) 에서 database의 종류에 대한 정보를 읽고 그 정보에 맞게 dao 인스턴스를 생성하여 실행될 수 있게 함

<package.hierarchy>

//UserInfo.java(사용자 정보 클래스)

package ch13.domain.userinfo;

public class Userinfo {
	private String userId;
	private String passwd;
	private String userName;
	public String getUserId() {
		return userId;
	}
	public void setUserId(String userId) {
		this.userId = userId;
	}
	public String getPasswd() {
		return passwd;
	}
	public void setPasswd(String passwd) {
		this.passwd = passwd;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	
	
}
// UserInfoDao.java ( dao 에서 제공되어야 할 메서드를 선언한 인터페이스 )

package ch13.domain.userinfo.dao;

// 같은 패키지가 아니기 때문에 import
import ch13.domain.userinfo.Userinfo;

public interface UserInfoDao {
	void insertUserInfo(Userinfo userInfo);
	void updateUserInfo(Userinfo userInfo);
	void deleteUserInfo(Userinfo userInfo);
}
// UserInfoMySqlDao.java (UserInfoDao 인터페이스를 구현한 MySql 버전 dao)

package ch13.domain.userinfo.dao.mysql;

import ch13.domain.userinfo.Userinfo;
import ch13.domain.userinfo.dao.UserInfoDao;

public class UserInfoMySqlDao implements UserInfoDao {

	@Override
	public void insertUserInfo(Userinfo userInfo) {
		System.out.println("Insert into MySQL DB userID = " + userInfo.getUserId());
		
	}

	@Override
	public void updateUserInfo(Userinfo userInfo) {
		System.out.println("Update into MySQL DB userID = " + userInfo.getUserId());
		
	}

	@Override
	public void deleteUserInfo(Userinfo userInfo) {
		System.out.println("delete into MySQL DB userID = " + userInfo.getUserId());
	}

}
// UserInfoOracleDao.java (UserInfoDao 인터페이스를 구현한 Oracle 버전 dao)

package ch13.domain.userinfo.dao.oracle;

import ch13.domain.userinfo.Userinfo;
import ch13.domain.userinfo.dao.UserInfoDao;

public class UserInfoOracleDao  implements UserInfoDao{

	@Override
	public void insertUserInfo(Userinfo userInfo) {
		System.out.println("insert into ORACLE DB userId =" + userInfo.getUserId() );
	}

	@Override
	public void updateUserInfo(Userinfo userInfo) {
		System.out.println("update into ORACLE DB userId = " + userInfo.getUserId());
	}

	@Override
	public void deleteUserInfo(Userinfo userInfo) {
		System.out.println("delete from ORACLE DB userId = " + userInfo.getUserId());
		
	}

}
// UserInfoClient.java (UserInfoDao 인터페이스를 활용하는 클라이언트 프로그램)

package ch13.userinfo.web;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

import ch13.domain.userinfo.Userinfo;
import ch13.domain.userinfo.dao.UserInfoDao;
import ch13.domain.userinfo.dao.mysql.UserInfoMySqlDao;
import ch13.domain.userinfo.dao.oracle.UserInfoOracleDao;

public class UserInfoClient {

	public static void main(String[] args) throws IOException {
		
        //주어진 fis 객체가 파일을 바이트 스트림으로 읽기 위한 FileInputStream 객체 생성
		FileInputStream fis = new FileInputStream("db.properties");
		
		// key-value 값 담
        //"Key = Value" 형태로 된 "파일이름.properties" 파일 또는 Xml 파일
		//	key를 주면 Value를 반환하는 기능을 가짐
		Properties  prop = new Properties();
		prop.load(fis);
		
		String dbType = prop.getProperty("DBTYPE");
		
		Userinfo userInfo = new Userinfo();
		userInfo.setUserId("12345");
		userInfo.setPasswd("!@#@!#!");
		userInfo.setUserName("Lee");
		
		UserInfoDao userInfoDao = null;
		
		if(dbType.equals("ORACLE")) {
			userInfoDao = new UserInfoOracleDao();
		}
		else if(dbType.equals("MYSQL")) {
			userInfoDao = new UserInfoMySqlDao();
		}
		else{
			System.out.println("db support error");
			return;
		}
		userInfoDao.insertUserInfo(userInfo);
		userInfoDao.updateUserInfo(userInfo);
		userInfoDao.deleteUserInfo(userInfo);

		
	}

}

여러 인터페이스 구현

diamond problem

예시)

grand father 이라는 클래스가 있고 father1, father2 두개의 클래스가 상속을 받은 상황이라 가정

이후 f1,f2를 child가 상속 받음

GF에 a();라는 메서드가 있는데 이를 f1,f2에서 오버라이드 함

Child c = new Child;
c.a();

이 경우 어느 메서드를 호출해야 하는지 의문

따라서 자바는 이러한 문제를 만들지 않기 위해 단일 상속

package ch15;

public interface Buy {

	void buy();
	
	default void order() {
		System.out.println("buy order");
	}
}
package ch15;

public interface Sell {
	void sell();
	
	default void order() {
		System.out.println("sell order");
	}
}
package ch15;

// 두개 이상의 인터페이스 구현
public class Customer implements Buy,Sell{

	@Override
	public void sell() {
		
		System.out.println("Customer Sell");
		
	}

	@Override
	public void buy() {
		System.out.println("Customer Buy");
		
	}

	public void hello() {
		System.out.println("Hello");
	}
	
	@Override
	// buy것 대신 sell의 디폴트 메서드를 쓰겠다는 의미
	public void order() {
		Sell.super.order();
	}
}
package ch15;

public class CustomerTest {

	public static void main(String[] args) {
		
		Customer customer = new Customer();
		customer.buy();
		customer.sell();
		customer.order();
		customer.hello();
		
        // 밑에 줄 의미 잘 숙지!
		Buy buyer = customer;
		
		// 재정의된 메서드가 호출됨으로 sell order 가 프린트 됨을 볼 수 있음.
		buyer.buy();
		buyer.order();
		
		Sell seller = customer;
		seller.sell();
		seller.order();
	}

}

클래스 상속과 인터페이스 구현 함께 쓰기

  • 책이 순서대로 대여가 되는 도서관 구현
  • 책을 보관하는 자료 구조가 Shelf에 구현됨 (ArrayList)
  • Queue 인터페이스를 구현함
  • Shelf 클래스를 상속 받고 Queue를 구현한다.
// shelf.java

package ch16;

import java.util.ArrayList;

public class Shelf {
	
	// 상속하여 사용하기 위해 protected
	protected ArrayList<String> shelf;
	
	public Shelf() {
		shelf = new ArrayList<String>();
	}
	
	public ArrayList<String> getShelf(){
		return shelf;
	}
	
	public int getCount() {
		return shelf.size();
	}
}
// Queue.java

package ch16;

public interface Queue {
	void enQueue(String title);
	String deQueue();
	
	int getSize();
}
package ch16;

public class BookShelf extends Shelf implements Queue {

	@Override
	public void enQueue(String title) {
		shelf.add(title);
		
	}

	@Override
	public String deQueue() {
		return shelf.remove(0);
	}

	@Override
	public int getSize() {
		return getCount();
	}

}
// bookshelftest.java

package ch16;

public class BookShelfTest {

	public static void main(String[] args) {
		
		Queue bookQueue = new BookShelf();
		bookQueue.enQueue("토지1");
		bookQueue.enQueue("토지2");
		bookQueue.enQueue("토지3");
		bookQueue.enQueue("토지4");
		bookQueue.enQueue("토지5");
		
		System.out.println(bookQueue.getSize());
		System.out.println(bookQueue.deQueue());
		System.out.println(bookQueue.deQueue());
		System.out.println(bookQueue.deQueue());
		System.out.println(bookQueue.deQueue());
		
		System.out.println(bookQueue.deQueue());
		

	}

}
profile
Journey for Backend Developer

0개의 댓글