공부

SOLID 원칙 공부하기

정훈5 2025. 1. 19. 20:05

 

목록

  1. Single Responsibility Principle 단일 책임 원칙
  2. Open-Closed Principle 개방-폐쇄 원칙
  3. Liskov Substitution Principle 리스코프 치환 원칙
  4. Interface Segregation Principle 인터페이스 분리 원칙
  5. Dependency Inversion Principle 의존 역전 원칙

  1. 단일 책임의 원칙
    1) 클래스는 하나의 책임(역할)만 가져야 한다.
    2) 변경의 이유가 하나뿐이어야 한다.

클래스

package Single;

public class EmailService {
	// 단일 책임 원칙을 적용한 클래스
	
	public void sendEmail(String email) {
		System.out.println("Email send to: " +email);
	} // end of sendEmail()
} // end of class
package Single;

public class UserService {
	// 단일 책임 원칙을 적용한 클래스
	
	public void createUser(String name) {
		System.out.println("User Created: " +name);
	} // end of createUser()
} // end of class

실행

package Single;

public class SingleTest {
	public static void main(String[] args) {
		
		UserService us = new UserService();
		us.createUser("고구마");
		
		EmailService es = new EmailService();
		
		es.sendEmail("이 문자가 들어갈까요?");
		
		
	} // end of main
} // end of class

실행 결과


  1. 개방-폐쇄 원칙
    1) 소프트웨어 확장에는 열려있고, 수정에는 닫혀 있어야 한다.
    2) 기존 코드를 수정하지 않고도 기능을 확장할 수 있어야 한다.

인터페이스

package Open;

public interface Payment {
	// 개방-폐쇄 원칙을 적용한 코드
	
	public void process();
} // end of interface

클래스

package Open;

public class PayPalPayment implements Payment{
	// 개방-폐쇄 원칙을 적용한 코드
	
	@Override
	public void process() {
		System.out.println("페이팔 결제 시스템");
	}
} // end of class

package Open;

public class CreditCardPayment implements Payment {
	// 개방-폐쇄 원칙을 적용한 코드
	
	@Override
	public void process() {
		System.out.println("신용카드 결제 시스템");
	}
}
package Open;

public class KakaoPayPayment implements Payment {

	@Override
	public void process() {
		System.out.println("카카오 결제 시스템");
	}
} // end of class

팩토리 클래스

package Open;

public class PaymentFactory {
	public static Payment getPayment (String type) {
		
		if(type.equalsIgnoreCase("credit")) {
			return new CreditCardPayment();
		} else if(type.equalsIgnoreCase("paypal")) {
			return new PayPalPayment();
		} else if(type.equalsIgnoreCase("kakao")) {
			return new KakaoPayPayment();
		}
		throw new IllegalArgumentException("Invaild payment type: " + type);
	} // end of getPayment
} // end of class

실행

package Open;

public class OpenTest {
	
	private Payment payment;
		
	public OpenTest(Payment payment) {
		this.payment = payment;
	} // end of 생성자
	
	// 결제 프로세스 진행
	public void processPayment() {
		payment.process();
	} // // 주입된 객체의 process() 실행
	
	public static void main(String[] args) {
		Payment payment1 = PaymentFactory.getPayment("credit");
		payment1.process();
		
		Payment payment2 = PaymentFactory.getPayment("paypal");
		payment2.process();
		
		Payment payment3 = PaymentFactory.getPayment("kakao");
		payment3.process();
		
	} // end of main
} // end of class

실행 결과


  1. 리스코프 치환 원칙
    1) 자식 클래스는 부모 클래스를 대체할 수 있어야 한다.
    2) 즉, 부모 클래스에서 정의한 기능이 자식 클래스에서도 동일하게 동작해야 한다.

추상적

package Liskov;

public abstract class Bird {
	
	public abstract void move(); 
} // end of class

클래스

package Liskov;

public class FlyingBird extends Bird {

	@Override
	public void move() {
		System.out.println("하늘을 날아서 이동");
	} // end of move()
} // end of class
package Liskov;

public class Penguin extends Bird {
	
	@Override
	public void move() {
		System.out.println("수영해서 이동");
	} // end of move()
} // end of class

실행

package Liskov;

public class LiskovTest {
	
	public static void main(String[] args) {
		
		FlyingBird FB = new FlyingBird();
		FB.move();
		
		Penguin Pg = new Penguin();
		Pg.move();
		
	} // end of main
} // end of class

실행 결과


  1. 인터페이스 분리 원칙
    1) 클라이언트는 자신이 사용하지 않는 메서드에 의존하지 않아야 한다.
    2) 여러 작은 인터페이스가 하나의 큰 인터페이스보다 낫다.

인터페이스

package Interface;

public interface Eatable {
	
	public void eat();
}
package Interface;

public interface Workable {
	
	public void work();
}

클래스

package Interface;

public class Human implements Workable, Eatable{
	
	@Override
	public void work() {
		System.out.println("Human Working");
	} // end of work()
	
	public void eat() {
		System.out.println("Human eating");
	} // end of eat()
} // end of class Human
package Interface;

public class Robot implements Workable {
	
	@Override
	public void work() {
		System.out.println("Robot working");
	}
} // end of Robot

실행

package Interface;

public class InterfaceTest {
	
	public static void main(String[] args) {
		
		Workable wa1 = new Human();
		Workable wa2 = new Robot();
		
		wa1.work();
		wa2.work();
		
		Eatable ea1 = new Human();
		ea1.eat();

		
	} // end of main
} // end of class

실행 결과


  1. 의존 역전 원칙
    1) 고수준 모듈이 저수준 모듈에 의존해서는 안 된다.
    2) 추상화된 인터페이스에 의존해야 한다.

고수준 모듈 : 인터페이스(Interface)추상(Abstract) 클래스 저수준 모듈 : 메인클래스객체

--> 추상화에 의존해야지 구체화에 의존하면 안된다 의미이다.

 

인터페이스

package Dependency;

public interface InputDevice {
	String getInput();
}

클래스

package Dependency;

public class Keyboard implements InputDevice {

	@Override
	public String getInput() {
		return "키보드 입력";
	}
}
package Dependency;

public class Mouse implements InputDevice {

	@Override
	public String getInput() {
		return "마우스 입력";
	}
}
package Dependency;

public class Computer {
	private InputDevice inputDevice;

	public Computer(InputDevice inputDevice) {
		this.inputDevice = inputDevice;
	}
	
	public void userInputDevice() {
		System.out.println(inputDevice.getInput());
	}
}

실행

package Dependency;

public class DependencyTest {
	
	public static void main(String[] args) {
		
		InputDevice keyboard = new Keyboard();
		InputDevice mouse = new Mouse();
		
		Computer computerKeyboard = new Computer(keyboard);
		computerKeyboard.userInputDevice();
		
		Computer computerMouse = new Computer(mouse);
		computerMouse.userInputDevice();
		
	}
}

실행 결과