수업내용/Java

[2022.09.23.금] 추상화, 인터페이스

주니어주니 2022. 9. 24. 00:05

 

1. 추상화

 

1-1. 추상화 개념

 

 

  • 의미
    • 구현부가 없는 메소드를 정의하는 것.
      (하위 구현클래스에게 메소드 구현을 위임시킴) 
  • 목적
    • 하위클래스(구현클래스)가 추상화된 메소드를 반드시 구현하도록 강제한다.
      (왜? 하위클래스는 추상화된 메소드를 보유할 수 없으니까 ) 
      (추상메소드로 꼭 필요한 기능들을 만들고, 하위클래스에서 그것들의 구현부를 재정의) 
    • 사용법이 동일한 하위객체를 만들게 하기 위함
    • (인터페이스가 맞다) : 똑같은 잭이 연결되는 것 (표준을 지킴)
// 구현클래스 - 구현메소드로 구성된 클래스, 추상화된 메소드를 보유할 수 없다. 
public class Sample {
               // 구현부가 있는 메소드 - 구현 메소드
              public void test1( ) { 
                         수행문;
                         수행문;
                         수행문;
              }


// 인터페이스 - 추상화된 메소드로 구성된 클래스 (표준) 
public interface Sample {
               // 구현부가 없는 메소드 - 추상 메소드
              public void test1( ) { 
              }

 

 

 

추상화

 

 

<인터페이스>

추상화된 메소드(구현부가 없는 메소드들)를 구현해놓은 인터페이스 => 자료구조 구현 클래스가 반드시 구현해야할 기능

public interface Collection {

    void add(Object ob);                   // 자료구조 객체에 새로운 객체를 추가한다.

    void remove(Object obj);            // 자료구조 객체에서 지정된 객체를 삭제한다.

    boolean contains(Object obj);    // 자료구조 객체에서 지정된 객체를 포함하고 있는지 여부를 반환한다.

    int size( );                                   // 자료구조 객체에 저장된 객체의 개수를 반환한다.

    void clear( );                              // 자료구조 객체에 저장된 모든 객체를 삭제한다

 } 

 

<구현 클래스 - ArrayList> 

인터페이스로부터 추상화 메소드를 상속받아서 자료구조를 ArrayList로 구현할거야 

( ArrayList - 가변길이의 배열을 이용한 자료구조 구현 클래스 )

여기에 상속받은 추상화된 메소드를 가져야되는데 구현클래스는 추상화된 메소드를 보유할 수없어 

--> 그러면 상속받은 모든 추상화메소드의 구현부를 반드시 재정의 해야함

 void add(Object ob); { 구현부 재정의 내용 }

 

<구현 클래스 - Stack>

( Stack - 선입후출 방식의 자료구조 구현 클래스 ) 

여기서도 반드시 상속받은 모든 추상화메소드의 구현부를 재정의해야함

 

 

자료구조라는 놈들은 모두 추가, 삭제 등의 기능을 갖고있어야 되잖아 (스펙 지정 (이런거 꼭 있어야돼)) 

자료구조 구현 클래스로 객체를 만들 때 같은 기능을 하는 놈들은 사용법이 똑같아야 되잖아 

( ex. 추가기능은 모두 add로 ) 

그러려면 -> 메소드 재정의를 강제시킨다. --> 이게 바로 추상화

사용법이 동일한 하위객체를 만들게 하기 위함

 

 

 


 

 

2. 인터페이스 

 

2-1. 인터페이스 개념

 

  • 인터페이스 하위 클래스에 특정한 메소드가 반드시 존재하도록 강제할 때 사용한다.
  • 인터페이스는 모든 하위 클래스의 사용법(메소드의 실행방법)을 통일시키는 표준으로 사용된다.
    그 표준을 정하는 방식이 추상화 (메소드 재정의의 강제력을 갖기 때문) 
  • 하위 클래스는 인터페이스에 정의된 추상화된 메소드를 구현(재정의)할 책임이 있다.
  • 하위 클래스는 동시에 여러 개의 인터페이스를 구현할 수 있다.

 

 

 

추상화의 활용

 

ex) 

회계 프로그램을 개발할거야 

리소스들을 엑셀, 데이터베이스, 클라우드 중 어디서 가져올지 몰라 

-> 일단 리소스를 구현하는 기능에 대한 표준을 정해버려

 

<인터페이스 (표준)> 

- 인터페이스를 만들고 추상화 메소드들을 만들어 (메소드 선언들을 먼저 해)

- 리소스를 읽어오는 기능은 모두 read, 쓰는 기능은 write, 삭제는 모두 remove 이어야 돼

 

<구현클래스> 

- 이 표준을 구현(상속)해서 구현클래스를 만들고, 원래는 없던 구현부를 만드는거야

- 리소스들이 인터페이스(표준)을 부모로 해 ( implements ) 

- 엑셀, 데이터베이스, 클라우드에서 가져온 데이터들의 구현부를 재정의해 

- 메소드 이름과 사용법은 똑같아(사용법을 같게 만드는게 = 메소드 재정의)  

 

<회계 프로그램> 

- 회계프로그램을 개발하는 사람은 인터페이스의 구현을 보고 코딩을 해  (참조) 

- 이제 부모객체인 인터페이스 객체를 참조할건데 아직 리소스들 중 어떤걸 연결할지 모르니까 

- Resource resource;   ( 부모객체인 Resource타입으로 연결 잭만 일단 만들어놔 ) 

- 그리고 이 회계프로그램 안에 데이터분석하는 메소드를 만들거야 

- void 데이터분석 ( ) {

     List<Data> data = resource.read( ); 

     processData(data);

  }

 -> resource가 가리키는 객체의 read메소드를 실행한 결과리스트를 data변수에 저장하고, process를 실행할거야 

 -> 그래서 그 리스트의 데이터를 가져올건데, Resource 객체(인터페이스)는 추상화메소드라서 실행을 할 수가 없어

 -> 그러면 이 인터페이스를 구현하는 클래스 중에 하나에서 데이터를 가져와야돼 

 -> 근데 인터페이스의 read 기능을 각 구현클래스마다 다르게 재정의를 해놨음

 -> 어떤 리소스(엑셀리소스, db리소스, ...)를 쓰느냐에 따라서 어느 구현클래스에 있는 read 기능을 쓰는지가 달라져 

     (Resource는 인터페이스라서 추상화메소드이고, 이걸 구현클래스에 따라서 다르게 재정의 해놨음) 

 -> 그래서 어떤 리소스를 가져올지 연결하기 위해 setter 메소드를 이용해 (전달받는 것들 - setter 메소드?) 

- void setResource(Resource r) { 

     this.resource = r;

  }

 -> Resource 타입의 객체를 r변수에 넣고, 이 r변수의 값을 회계프로그램 객체의 resource에 대입

     ( Resource 객체를 회계프로그램에 연결

 -> setResource의 매개변수가 Resoucre라는 객체를 요구는건데 

 -> 인터페이스 객체에는 구현부가 없어 -> 객체 생성을 못해 -> 이 인터페이스를 구현하는 객체를 달라는 뜻

     ( 얘네도 Resource를 상속받아서 만든거니까 Resource객체를 갖고있음 )

 -> 구현클래스를 구현하면, 그걸가지고 실제로 구현하는 객체를 만들거야 -> 그 안에 인터페이스, 구현클래스의 내용있음

     ( 실행객체에 상위클래스인 Resource가 있음 ) 

 -> 회계프로그램의 resource 변수가 연결하는건, 실제 구현하는 객체의 상위클래스인 Resource객체 

 -> 그러면 똑같은 기능들을 모두 재정의한거니까, 메소드재정의에 의해서 그 실제 구현하는 객체의 read기능이 실행됨 

 

(같은 인터페이스를 가지고 구현을 하면, 똑같은 사용법으로 객체만 다르게 연결을 해주면 돼 )

 

 

 

자동차 제조사가 있고 

차체 제조사 , 부품 제조사가 있어 

자동차 문 사양(스펙, 표준)을 제작해서 -> 부품제조사한테 줘 -> 차체 제조사한테도 줘 

-> 문 사양을 보고, 부품 제조사에서 문을 만들어

어떤 차에 어떤 문 부품이 조립될지 몰라 

부품제조사, 자체 제조사가 같은 표준을 보고 만든거니까 -> 뭘 조립하든 다 조립이 되고, 사용법도 다 같아

 

 

 

 

실습) 

 

  • 인터페이스 Chart (꼭 가져야 하는 기능(메소드)들 선언
public interface Chart {			// 인터페이스(표준)- 꼭 가져야 하는 메소드 선언

	// 구현부가 없는 주상메소드 
   	// 데이터 전달받는기능, 타이틀 전달받는기능, 열이름 전달받는기능
	void setData(int[] data);		// data 배열 전달받는 기능
	void setTitle(String title);
	void setColumnNames(String[] columnNames);
	void drawChart(); 
}
  • 하위 인터페이스 BarChart 
public class BarChart implements Chart {	// Chart인터페이스를 구현하는 구현클래스
	
	private int[] data;
	private String title;
	private String[] columnNames;
	
	public void setData(int[] data) {	
		this.data = data; 
	}
	public void setTitle(String title) { 
		this.title = title; 
	}
	public void setColumnNames(String[] columnNames) {
		this.columnNames = columnNames;
	}
	public void drawChart() {
		System.out.println("### BarChart ###");
		System.out.println("<< " + title + " >>");
		
		for(int index = 0; index<columnNames.length; index++) {		// 'columnNames'배열의 길이만큼 반복
			System.out.print("["+columnNames[index]+"]");		// columnNames배열의 index번째를 꺼내기
			for(int value = 0; value<data[index]; value++) {	// 'data'배열의 각 값만큼 반복 (data배열의 index번째 값)
				System.out.print("■");
			}
			System.out.println();
		}
	}

}
  • 하위 인터페이스 LineChart
public class LineChart implements Chart {

	private int[] data;
	private String title; 
	private String[] columnNames;
	
	public void setData(int[] data) {
		this.data = data; 
	}
	public void setTitle(String title) {
		this.title = title; 
	}
	public void setColumnNames(String[] columnNames) {
		this.columnNames = columnNames;
	}
	public void drawChart() {
		System.out.println("### Line Chart ###");
		System.out.println("<< "+ title + " >>");
		
		for(int index=0; index<columnNames.length; index++) {
			System.out.print("["+columnNames[index]+"]");
			for(int value = 0; value < data[index]; value++) {
				System.out.print(" ");
			}
			System.out.println("|");
		}
	}
	
}

 

public class ChartApp {
	
	public static void main(String[] args) {
		Chart chart = new LineChart();	// 같은 표준을 가지고 만들어서, 사용방법내용은 똑같고 객체만 바꾸면 돼 
		chart.setData(new int[] {10, 25, 7, 30});
		chart.setTitle("2021년 분기별 순이익 (단위: 억원)");
		chart.setColumnNames(new String[] {"1분기", "2분기", "3분기", "4분기"} );
		chart.drawChart();
		
	}
}

 

### BarChart ###
<< 2021년 분기별 순이익 (단위: 억원) >>
[1분기]■■■■■■■■■■
[2분기]■■■■■■■■■■■■■■■■■■■■■■■■■
[3분기]■■■■■■■
[4분기]■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

 

### Line Chart ###
<< 2021년 분기별 순이익 (단위: 억원) >>
[1분기]          |
[2분기]                         |
[3분기]       |
[4분기]                              |

 

 

 

 

 

2-2. 상속과 구현 

 

 

상속과 구현

 

상속과 구현

 

 

  • 상속(extends)과 구현(implements)의 차이

    • <상속>

      상위 클래스              : 공통 속성 정의, 공통 기능 구현                    

              ↓                         
      상속 (extends)          (기능을 높이고 싶으면 메소드 재정의, 근데 안하고 그대로 사용해도 돼 )                         
              
      하위 클래스              : 부모의 기능 상속 + 고유의 속성과 기능 정의 

      • 상속의 목적
        - 반복코드 제거
        - 하위 클래스의 빠른 개발
        - 공통속성과 공통기능의 재사용성 증가
        - 유지보수성 향상

    • <구현>

      상위 인터페이스                : 구현할 기능의 사양만 정의 (추상화된 메소드) 
               ↓                     
      구현(implements)              print 메소드를 재정의를 안하고, 다른 메소드 이름을 쓰면 -> 컴파일 오류 
                                                  (사용법을 다르게 쓰는걸 허용 X -> 메소드 재정의 무조건 해야돼 )
               ↓
      하위 구현 클래스               : 추상화된 기능의 구현 (추상화된 메소드 재정의) 

                                                  (구현 내용은 다르지만, 구현 방법이 동일한 구현 메소드) 
      • 구현의 목적 
        - 사용방법이 동일한 하위 구현클래스의 작성

 

 

 

  • 구현시, 재정의된 기능과 고유 기능의 차이

재정의된 기능과 고유 기능의 차이

 

메소드 재정의를 하려면, 최소한 그 메소드를 가지고 있는 객체부터 참조를 해야 함

하위 인터페이스의 고유기능을 사용하려면 그 기능이 있는 객체를 바라봐야함 

그 고유의 기능이 상위 인터페이스에 없다면 -> 메소드 재정의 불가능

재정의 된거는 Collection을 바라봐도 실행가능한데, 재정의 안되어있는 거는 반드시 그 객체를 바라봐야함
(재정의가 됐다는 것은 -> 상위, 하위 인터페이스에 모두 있다는 뜻) 

콜렉션에 있는 기능이 아니니까 메소드들을 사용할수없어

실제로 만든건 ArraryList인데, 인터페이스 Collection이 참조하는건 ArrayList안에 있는 Collection

내가 ArrayList에 있는 기능을 꼭 써야돼 -> 그러면 Collection에 담으면 안됨

 

* c1 참조변수는 ArrayList객체의 고유기능을 사용할 수 없다. (Collection에 없으니까 재정의 불가능) 

* c1 참조변수는 Collection에 정의되어 있고, ArrayList에 재정의된 것만 사용가능하다.

  (재정의 -> 상,하위 인터페이스에 모두 있다는 뜻이니까) 

 

 

 

2-2. 인터페이스와 클래스의 관계

 

인터페이스와 클래스

 

 

- 클래스와 클래스 간의 상속은 단일 상속만 허용

- 인터페이스와 인터페이스 간의 상속은 다중 상속을 허용

- 인터페이스와 클래스는 구현관계만 허용한다. (상속x)

- 클래스는 한번에 여러 개의 인터페이스를 구현 가능하다. 

 

(상속은 같은 타입끼리, 구현은 인터페이스와 클래스 간) 

 

 

 

 

 

인터페이스타입의 참조변수

 

상위클래스, 상위 인터페이스는 구현객체를 참조할 수 있다.

 

ex) 하나의 클래스가 클래스 하나를 상속받고, 인터페이스 두개를 구현하는거 

 

<Genesis 클래스> 

Car 클래스의 상속 + AirConditionable과 AutoDrivable 인터페이스를 구현

그러면 일단

에어컨 기능 구현, 자율주행 기능 구현 메소드 재정의를 해

 

<실행클래스> 

Genesis g1 = new Genesis();                 // g1이 바라보는 건 Genesis 객체

Car g2 = new Genesis();                         // g2가 바라보는 건 Genesis의 상위객체인 Car 객체

Airconditionable g3 = new Genesis();   // g3이 바라보는 건 AirConditionable인터페이스 -> 근데 재정의된 메소드 실행

AutoDrivalbe g4 = new Genesis();         // g4가 바라보는 건 AuboDrivable인터페이스 -> 근데 재정의된 메소드 실행

얘네가 다 가능해 (모두 genesis의 상위이기 때문)

g1일 때는, 기능 다 사용 가능 

g2일 때는, Car객체의 기능인 drive, stop만 사용 가능 

g3일 때는, AirConditionable 인터페이스의 기능만 사용 가능

g4일 때는, AutoDrivable 인터페이스의 기능만 사용 가능 

 

 

 

 

-Car 클래스

public class Car {		//운전, 속도변경, 속도업다운 기능

	private int speed;
	
	public void drive() {
		System.out.println("운전 기능 실행 중 ...");
	}
	
	public void changeSpeed(int speed) {
		this.speed += speed;
		System.out.println("현재 속도: "+this.speed);
	}
	
	public void speedUp() {
		if(speed == 300) {
			return;
		}
		speed += 10;
		System.out.println("현재 속도: " + speed);
	}
	
	public void speedDown() {
		if(speed == 0) {
			return;
		}
		speed -= 10;
		System.out.println("현재 속도: " + speed);
	}
	
}

-인터페이스 

public interface AirConditionable {

	void aircon();
}

-인터페이스

public interface AutoDrivable {

	void autoDrive();
}

-Car클래스 상속, 인터페이스 구현

public class Genesis extends Car implements AirConditionable, AutoDrivable {

	// 제네시스의 고유 기능
	public void cinema() {
		System.out.println("제네시스의 영화 감상 기능 실행 중...");
	}
	
	@Override
	public void speedUp() {		// Car의 speedUp 메소드 재정의 
		changeSpeed(50);
		System.out.println("제네시스의 속도 증가기능 실행 중...");
	}
	
	@Override
	public void speedDown() {
		changeSpeed(-50);
		System.out.println("제네시스의 속도 감소기능 실행 중...");
	}
	
	@Override 	// 메소드재정의. 추상화된 메소드 구현 아직 안하면 빨간줄 -> 그거 누르면 자동으로 뜸 
	public void autoDrive() {
		System.out.println("제네시스의 자율 주행 기능 실행 중...");
		
	}

	@Override
	public void aircon() {
		System.out.println("제네시스의 온도 조절 및 공기 청정기능 실행 중...");
		
	}
}

-실행객체 

public class CarApp {

	public static void main(String[] args) {
		
		System.out.println("### Genesis 타입 참조변수로 참조");
		Genesis g1 = new Genesis();
		g1.cinema();		// Genesis 고유 기능 사용가능
		g1.drive();		// Car의 기능 사용가능
		g1.changeSpeed(50);	// Car의 기능 사용가능
		g1.speedUp();		// Car의 기능 사용가능
		g1.speedDown();		// Car의 기능 사용가능
		g1.autoDrive();		// AutoDrivable의 사양(추상화된 기능 구현(재정의))
		g1.aircon();		// AirConditionable의 사양(추상화된 기능 구현(재정의))
		
		System.out.println("### Car 타입 참조변수로 참조");
		Car g2 = new Genesis();
//		g2.cinema();		// Genesis 고유 기능 사용가능
		g2.drive();		// Car의 기능 사용가능
		g2.speedUp();		// Car의 기능 사용가능
		g2.speedDown();		// Car의 기능 사용가능
//		g2.autoDrive();		// AutoDrivable의 사양(추상화된 기능 구현(재정의))
//		g2.aircon();		// AirConditionable의 사양(추상화된 기능 구현(재정의))
		
		System.out.println("### AutoDrivable 타입 참조변수로 참조");
		AutoDrivable g3 = new Genesis();
//		g3.cinema();		// Genesis 고유 기능 사용가능
//		g3.drive();		// Car의 기능 사용가능
//		g3.speedUp();		// Car의 기능 사용가능
//		g3.speedDown();		// Car의 기능 사용가능
		g3.autoDrive();		// AutoDrivable의 사양(추상화된 기능 구현(재정의))
//		g3.aircon();		// AirConditionable의 사양(추상화된 기능 구현(재정의))
		
		System.out.println("### AirConditionable 타입 참조변수로 참조");
		AirConditionable g4 = new Genesis(); 
//		g4.cinema();		// Genesis 고유 기능 사용가능
//		g4.drive();		// Car의 기능 사용가능
//		g4.speedUp();		// Car의 기능 사용가능
//		g4.speedDown();		// Car의 기능 사용가능
//		g4.autoDrive();		// AutoDrivable의 사양(추상화된 기능 구현(재정의))
		g4.aircon();		// AirConditionable의 사양(추상화된 기능 구현(재정의))
	}
}

 

### Genesis 타입 참조변수로 참조
제네시스의 영화 감상 기능 실행 중...
운전 기능 실행 중 ...
현재 속도: 50
제네시스의 속도 증가기능 실행 중...
현재 속도: 100
제네시스의 속도 증가기능 실행 중...
현재 속도: 50
제네시스의 속도 감소기능 실행 중...
제네시스의 자율 주행 기능 실행 중...
제네시스의 온도 조절 및 공기 청정기능 실행 중...

### Car 타입 참조변수로 참조
운전 기능 실행 중 ...
현재 속도: 50
제네시스의 속도 증가기능 실행 중...
현재 속도: 100
제네시스의 속도 증가기능 실행 중...
현재 속도: 50
제네시스의 속도 감소기능 실행 중...

### AutoDrivable 타입 참조변수로 참조
제네시스의 자율 주행 기능 실행 중...

### AirConditionable 타입 참조변수로 참조
제네시스의 온도 조절 및 공기 청정기능 실행 중...

 

 

 

 

인터페이스를 구현할 건데

public class 제네시스 extends Car implements 오디오가능한, 에어백나오는, 길안내가능한, 자율주행가능한, ....  {

구현해야될 인터페이스가 많으면?? 너무 길어지잖아

근데 만약 한 인터페이스에 기능을 다 몰아넣고, 구현하지 않는 기능은 재정의 안하고 냅두는 식으로 하면

-> 기능이 너무 몰려있고, 구현하지 않아야 되는 사양까지 있는데 뭘 구현하는지 판단하지 못할수도 있음 

 

그러면 이렇게 함 ( 2개 이상의 인터페이스를 조합 -> 새로운 사양 ) 

상위 인터페이스에서 

public interfce 소형차만드는 extends 오디오가능한, 에어백나오는 { }

이렇게 하고 

public class 모닝 extends Car implements 소형차만드는 {

    void 오디오() { 수동오디오를 재생합니다. };

    void 에어백() { 에어백 3개가 펼쳐집니다. };

}

 

public interfce 형차만드는 extends 소형차만드는, 길안내가능한, 공기청정가능한 { }

이렇게 만들고 

public class 제네시스 extends Car implements 중형차만드는 {

    void 오디오() { 자동오디오를 재생합니다. };

    void 에어백() { 에어백 5개가 펼쳐집니다. };

    void 길안내() { 길안내를 시작합니다. };

    void 공기청정() { 공기청정 기능이 켜집니다. };

}

 

--> 구현범위가 명확

특정 인터페이스를 구현한다는 것은 -> 아 그 기능을 이용할 수 있겠네 

 

 

 

 

3. 추상화와 인터페이스 

 

 

3-1. 추상화와 인터페이스 

 

  • 추상화
    • 구현부가 없는 메소드를 정의하는 것
      (하위 구현클래스에게 메소드 구현을 위임시킴)
    • 사용방법이 동일한 하위 구현클래스를 구현하게 한다.
  • 인터페이스
    • 추상화의 수단
    • 하위 구현클래스가 구현할 기능의 사양을 정의
      (구현부가 없는 메소드는 반환타입, 메소드명, 매개변수의 종류를 지정 <--- 메소드의 사양)
    • 구현부가 없는 메소드와 상수만 포함할 수 있다.  
      (Java 8부터는 구현부가 있는 디폴트 메소드도 포함할 수 있다.) 
    • new 연산자를 이용해서 객체 생성할 수 없다. (내가 만들 수가 없다) 
    • 인터페이스에 정의되는 추상메소드는 abstract 키워드를 보통 생략한다.
  • 추상클래스
    • 구현메소드와 추상메소드를 모두 포함할 수 있는 클래스
    • 일반 구현클래스의 모든 구성요소(멤버변수, 클래스변수, 생성자, 멤버메소드, 클래스메소드)를 포함할 수 있다.
      (일반 구현클래스랑 완전 똑같은데, 거기다가  + 추상메소드도 포함)
    • new 연산자를 이용해서 객체 생성할 수 없다.
    • 클래스 선언부에 abstract 키워드 포함
    • 추상클래스에 정의되는 추상메소드는 반드시 abstract 키워드를 포함해야 한다. 
    • 형식
      • public abstract class 클래스명 {
                  // 추상메소드를 포함할 수 있다.
                  public abstract int read( ); 

                  // 구현메소드도 포함할 수 있다.
                  public int read(byte[] buf) {
                                 ...
                  } 
        }
  • 추상메소드
    • 구현부가 없는 메소드 
    • 형식
      • 접근제한자 abstract 반환타입 메소드명(매개변수타입 변수명, 매개변수타입 변수명, ...);
        단, 인터페이스에서는 접근제한자와 abstract 키워드를 생략할 수 있다.
             ( 생략되어 있으면 기본적으로 public abstract가 생략된 거라고 생각 ) 

      • 예시)
        public abstract int size( );
        public abstract boolean add(Object obj);
        public abstract boolean isEmpty( );
        void aircon( ); 

 

 

3-2. 추상클래스 (살짝) 

 

 

<Chart 인터페이스> -추상화메소드를 포함 

public interface Chart {  
    void setData(int[] data); 
    void setTitle(String title);
    void setColumnNames(String[] columnNames);
    void drawChart(); 
}

 

 

 

1) 추상클래스가 없을 때 - 그래프로 그리는 부분 제외하면 구현클래스의 코드가 똑같아

 

추상클래스 없이 인터페이스 구현하기

 

<BarChart 구현클래스>

public class BarChart implements Chart {                            // Chart 인터페이스를 구현

    private int[] data;
    private String title;
    private String[] columnNames;

public void setData(int[] data) {
    this.data = data; 
    }
public void setTitle(String title) { 
    this.title = title; 
    }
public void setColumnNames(String[] columnNames) {
    this.columnNames = columnNames;
    }                                                                                         ---> 이 부분을 구현클래스마다 싹다 일일이 구현해야돼 
public void drawChart() {

    // 막대그래프로 그리기

    }

}

 

 

 

 

2) 추상클래스 있을 때 

 

추상클래스를 사용해서 인터페이스 구현하기

 

<Chart 인터페이스>

반드시 가져야 하는 기능을 추상화메소드로 적음

 

 

<AbstractChart 추상클래스>

public abstract class AbstractChart implements Chart {              // Chart 인터페이스를 구현

-> 공통된 기능들 구현

 

추상클래스는 구현부가 없는 추상메소드도 보유 할 수 있음 ( void drawChart( ) ; 도 있어 )

-> 이건 각 구현클래스에서 구현함

 

 

<BarChart 구현클래스> 

public class BarChart extends AbstractChart {

     public void drawChart ( 

     // 막대그래프로 그리기

     } 

}

각 구현클래스에서는 추상클래스를 상속받고, 각각 다른 기능만 구현하면 됨

-----> 추상클래스가 인터페이스와 구현클래스의 사이에 위치해서, 구현클래스의 구현부담을 감소시킬 수 있다. 

 

 

 

 

 

 

 

 

* 객체지향 개발 5대 원칙 (SOLID)

S (단일 책임) - 너는 선언기능만, 너는 업무로직기능만, 너는 실행기능만해 (각자 맡은일만 함)

O (개방폐쇄) - 확장에 열려있고, 변화에 닫혀있음 ( 다형성 ) 

I  (분리 원칙)  - 자신이 사용하지 않는 인터페이스는 구현하지 않아야 한다. 필요한 인터페이스별로 분리해서 사용 

D (의존성 역전 원칙) - 연결잭에 객체를 직접 넣거나, 제3자로부터 받아서 주입하거나