본문 바로가기
Java/Java language

[JAVA]11. 객체지향 프로그래밍(OOP)의 SOLID 5대원칙?

by oomm112 2022. 3. 11.

객체지향 프로그래밍(OOP : Object-Oriented Programming)이란?

현실의 사물들을 객체로 보고 프로그래밍 하는 기법이며, 5원칙이 존재한다.[SOLID]

  1. 단일 책임 원칙(SRP) : 클래스는 단 하나의 목적을 가져야하며, 변경 이유도 단 하나 여야만 한다.
  2. 개방 폐쇄 원칙(OCP) : 클래스는 확장에는 열려 있고, 변경에는 닫혀있어야만 한다.
  3. 리스코프 치환 원칙(LSP) : 상위 타입의 객체를 하위타입의 객체로 변경하여도 일관되게 동작 하여야 한다.
  4. 인터페이스 분리 원칙(ISP) : 목적과 관심에 맞게 인터페이스를 적절하게 분리해 주어야 한다.
  5. 의존 역전 원칙 (DIP) : 추상화에 의지하고, 구체화(구현클래스)에 의지 하면 안된다.
반응형

A. 단일 책임 원칙(SRP)?

클래스는 단 하나의 목적을 가져야 한다 = > 즉, 하나의 클래스가 여러개의 역할을 해서는 안된다.

책임을 가지는 액터가 한 명일 경우에는 상관없지만, 여러명으로 분리되어 있을경우에는 책임을 나눠주어야한다.

 

ex) 만약 프로그램을 만드는 액터가 이미지를 그리는 디자이너 / 프로그램을 개발하는 개발자 / 음악을 만드는 아티스트가 있습니다.

 

//이 코드는 단일 책임 원칙을 지키지 않은 코드입니다.
class programm{
	void drawImage(){
    	"프로그램에 필요한 이미지를 그립니다"
    }
    
    void developProgramm(){
    	"프로그램의 백엔드를 개발합니다"
    }
    
    void makeMusic(){
    	"프로그램에 필요한 음악을 만듭니다"
    }
    
    //이 코드에서는 한 프로그램안에 세개의 액터의 책임을 가지고 있습니다.
}

 


//아래 코드는 디자이너 / 개발자 / 아티스트 로 책임을 나누어 주었습니다. 

class Designer{
	void drawImage(){
    	"그림을 그립니다"
    }
}

class Developer{
	void developProgramm(){
    	"프로그램의 백엔드를 개발합니다"
    }
}

class Artist{
	void makeMusic(){
    	"프로그램에 필요한 음악을 만듭니다"
    }
}

B. 개방 폐쇄 원칙(OCP)?

개방 폐쇄 원칙이란 확장에는 열려 있으나, 변경에는 닫혀 있어야만 한다.

=> 즉, 코드의 수정을 하지 않되, 기능 변경과 확장을 사용할 수 있어야 한다.

 

a) 보통 OCP를 지키기 위해서는 추상화와 상속을 이용하는 것이다.

//아래 처럼 컴퓨터에 키보드와 모니터를 연결할 수 있다고 가정한다
class Computer{
	String keyboard = "S키보드";
    String monitor = "L모니터";
    
    System.out.println(monitor + "를 장착합니다.");
    System.out.println(keyboard + "를 장착합니다.");
}

위 코드 같은 경우에는 OCP원칙을 지키지 못한 코드이다. 기능을 수정하려면 코드를 바꿔야 하기 떄문이다.


//아래 코드는 OCP원칙을 지켜 기능을 추가 할때 코드의 변경이 필요 없다.
class Computer implements Keyboard, Monitor{
	private String monitor;
	private String keyboard;
	
	void setMonitor(String monitor) {
		this.monitor = monitor;
	}
	
	void setKeyboard(String Keyboard) {
		this.keyboard = keyboard;
	}

	@Override
	public void getMonitor() {
		System.out.println(monitor + "를 장착합니다.");	
	}

	@Override
	public void getKeyboard() {
		System.out.println(keyboard + "를 장착합니다.");	
	}
	
}

interface Keyboard{
	void getKeyboard();
}

interface Monitor{
	void getMonitor();
}

위 코드는 인터페이스를 상속 받아서, 값을 수정해줄 필요가 없이 인터페이스를 수정 해주면 된다.

 


C. 리스코프 치환 원칙(LSP)?

상위 타입의 객체를 하위타입의 객체로 변경하여도 일관되게 동작 하여야 한다.

 

ex) 고양이와 강아지는 동물에 속합니다, 그렇다면 고양이와 강아지는 동물 이라고 할수있겠죠?

 


D. 인터페이스 분리 원칙(ISP)?

목적과 관심에 맞게 인터페이스를 적절하게 분리해 주어야 한다.

즉, 인터페이스를 상속받는 클래스가 필요치 않는 메소드를 구현 하지 않고, 필요한 메소드만을 구현해야한다.

 

ex) 아래 예제로 사람 인터페이스를 상속받는 A와 B가 있습니다. A는 판매자가 아니고, B는 판매자라고 가정해봅시다.

 

아래 예제를 보면 A는 판매자가 아니기 때문에, sell메소드는 필요가 없는 메소드입니다.

그렇다면 아래 예제는 ISP원칙을 지키지 못한것입니다.

//ISP에 어긋나는 코드

interface Person{
	void eat();
    void sleep();
    void buy();
    void sell();
}

public class PersonA implements Person{
	@Override
	public void eat() {}
	
	@Override
	public void sleep() {}

	@Override
	public void buy() {}

	@Override
	public void sell() {}	//판매자가 아니므로 필요 없는 메소드임.
}

//판매자
class PersonB implements Person{
	@Override
	public void eat() {}
	
	@Override
	public void sleep() {}

	@Override
	public void buy() {}

	@Override
	public void sell() {}

}

하지만 아래 형식으로 만든다면? 판매자가 아닌 A는 sell메소드를 필요치 않으니 구현하지 않게되고

B는 판매자이자 사람이기 때문에, Person인터페이스와 Seller인터페이스를 통해 구현하게 됩니다

//ISP를 준수하는 코드

interface Person{
	void eat();
    void sleep();
    void buy();
}

interface Seller{
	void sell();
}

public class PersonA implements Person{
	@Override
	public void eat() {}
	
	@Override
	public void sleep() {}

	@Override
	public void buy() {}
}

class PersonB implements Person, Seller{
	@Override
	public void eat() {}
	
	@Override
	public void sleep() {}

	@Override
	public void buy() {}

	@Override
	public void sell() {}

}

 

 


E. 의존 역전 원칙 (DIP)?

추상화에 의지하고, 구체화(구현클래스)에 의지 하면 안된다. 

객체는 저수준 모듈보다 고수준 모듈에 의존해야 한다!!

출저 : https://steady-coding.tistory.com/388

위 예제를 보면 자동차의 한 부분인 타이어 = > 고수준 모듈 = 자동차 / 저수준 모듈 = 타이어 로 볼수있습니다.

아래 타이어 인터페이스를 상속받는 스노우타이어/일반타이어/광폭타이어 들은 타이어 인터페이스를 의존하게 됩니다.

 

여기서 타이어는 저수준 모듈보다는 고수준 모듈인 자동차 입장에서 만들어지는데, 이것은 고수준 모듈이 저수준 모듈에 의존했던 상황이 역전되어 저수준 모듈이 고수준 모듈에 의존하게 된다는 것을 의미합니다. 이런 맥락에서 이 원칙의 이름이 의존 역전 원칙인 것입니다.

다만,
 
소스 코드의 의존
은 자동차가 '타이어'를 의존하지만, 런타임에서의 객체 의존은 타이어가 아니라
하위 타이어 중 하나를 의존합니다. 따라서, 의존 역전 원칙은 런타임에서의 의존을 역전시키는 것이 아니라
 소스 코드 단계에서의 의존을 역전시킨다는 것을 유의해야 합니다.

출저 : https://steady-coding.tistory.com/388

 

 

위 글에서 고칠점이나 추가할점 & 의견 있으시면 댓글 부탁드립니다! 감사합니다!

반응형

댓글