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) {
...
}
}
- public abstract class 클래스명 {
- 추상메소드
- 구현부가 없는 메소드
- 형식
- 접근제한자 abstract 반환타입 메소드명(매개변수타입 변수명, 매개변수타입 변수명, ...);
단, 인터페이스에서는 접근제한자와 abstract 키워드를 생략할 수 있다.
( 생략되어 있으면 기본적으로 public abstract가 생략된 거라고 생각 ) - 예시)
public abstract int size( );
public abstract boolean add(Object obj);
public abstract boolean isEmpty( );
void aircon( );
- 접근제한자 abstract 반환타입 메소드명(매개변수타입 변수명, 매개변수타입 변수명, ...);
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 (개방폐쇄) - 확장에 열려있고, 변화에 닫혀있음 ( 다형성 )
L
I (분리 원칙) - 자신이 사용하지 않는 인터페이스는 구현하지 않아야 한다. 필요한 인터페이스별로 분리해서 사용
D (의존성 역전 원칙) - 연결잭에 객체를 직접 넣거나, 제3자로부터 받아서 주입하거나
'수업내용 > Java' 카테고리의 다른 글
[2022.09.27.화] Object 클래스, String 클래스 (0) | 2022.09.28 |
---|---|
[2022.09.26.월] 추상화클래스 활용 (0) | 2022.09.26 |
[2022.09.22.목] 강제 형변환, 메소드 재정의와 다형성 (0) | 2022.09.22 |
[2022.09.21.수] 생성자 메소드, 클래스형변환 (0) | 2022.09.21 |
[2022.09.20.화] static, 상속 (0) | 2022.09.20 |