
SRP
하나의 클래스는 하나의 책임만 가져야한다
public class User {
private String username;
private String password;
public User(String username, String password) {
this.username = username;
this.password = password;
}
public boolean isValid() {
// 유효성 검사
return true;
}
public void save() {
// 데이터 저장
}
}
public class User {
private String username;
private String password;
public User(String username, String password) {
this.username = username;
this.password = password;
}
}
public class UserValidator {
public boolean isValid(User user) {
// 유효성 검사
return true;
}
}
public class UserDAO {
public void save(User user) {
// 데이터 저장
}
}
OCP
확장에는 열려있고 변경에는 닫혀있어야한다
public interface Shape {
double calculateArea();
}
public class Circle implements Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
public double calculateArea() {
return Math.PI * radius * radius;
}
}
public class Rectangle implements Shape {
private double width;
private double height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
public double calculateArea() {
return width * height;
}
}
public class AreaCalculator {
public double calculateArea(Shape[] shapes) {
double totalArea = 0;
for (Shape shape : shapes) {
totalArea += shape.calculateArea();
}
return totalArea;
}
}
Shape : 다양한 도형의 면적을 계산하기 위해 공통 기능 정의
Circle , Rectangle : 각각 원과 사각형의 면적을 계산하는 구체적인 기능 구현
AreaCalculator : 입력받은 여러 도형의 면적을 모두 더해 총 면적 계산 -> Shape 인터페이스를 구현한 어떤 도형 클래스도 입력으로 받을 수 있다.
따라, 어떤 새로운 도형 클래스가 추가되더라도 AreaCalculator는 수정할 필요가 X
OCP를 준수한 설계
LSP
자식 클래스가 부모 클래스의 인스턴스 대신 사용될 때 언제나 정상적으로 작동해야한다
public class PrintPositiveNum {
private int num;
public PrintPositiveNum(int num){
this.num = num;
}
public getNum(){
if(this.num <= 0){
throw new RuntimeException("0 이하는 출력 불가능!!!");
}
return this.num;
}
}
public class PrintNum extends PrintPositiveNum {
@Override
public getNum(){
return this.num;
}
}
public class Client{
public static void main(String[] args){
PrintPositiveNum obj = new PrintPositiveNum(1);
obj.getNum();
}
}
PrintPositiveNum (부모클래스) : 양수만 화면에 출력 가능
PrintNum (자식클래스) : 모든 범위의 숫자 출력 가능
Client가 양수를 주는 경우에는 문제가 없으나, 음수나 0을 주는 경우에는 Client 측 코드를 수정해야하만 실행을 보장한다.
이는 자식은 수행가능한데 부모는 수행 불가능하기 때문에 발생한다.
부모가 수행 가능한 범위 내에서만 오버라이딩을 해야 클라이언트 측 코드를 고칠 필요가 없어진다는 것이 핵심적인 내용이다.
ISP
클라이언트가 자신이 사용하지 않는 메서드에 의존하지 않도록 인터페이스를 작게 분리하는 것
public interface Shape {
double calculateArea();
double calculateVolume();
}
public class Rectangle implements Shape {
private double width;
private double height;
public double calculateArea() {
return width * height;
}
public double calculateVolume() {
throw new UnsupportedOperationException();
}
}
public class Cube implements Shape {
private double width;
private double height;
private double depth;
public double calculateArea() {
return 2 * (width * height + width * depth + height * depth);
}
public double calculateVolume() {
return width * height * depth;
}
}
Shape : 도형의 면적과 부피 계산하는 두 가지 메서드 정의
Rectangle : 면적만 계산하고 부피 계산 불가
클라이언트는 Shape 인터페이스를 구현한 모든 클래스에서 부피 계산 메서드를 사용하기 때문에 불필요한 의존성이 생긴다
public interface Area {
double calculateArea();
}
public interface Volume {
double calculateVolume();
}
public class Rectangle implements Area {
private double width;
private double height;
public double calculateArea() {
return width * height;
}
}
public class Cube implements Area, Volume {
private double width;
private double height;
private double depth;
public double calculateArea() {
return 2 * (width * height + width * depth + height * depth);
}
public double calculateVolume() {
return width * height * depth;
}
}
DIP
상위 객체는 하위 객체의 구체성에 의존해서는 안되며 추상화에 의존해야 한다
public class RedLight {
public void turnOn() {
System.out.println("Red Light turned on");
}
}
public class Switch {
private RedLight light;
public Switch() {
this.light = new RedLight();
}
public void flip() {
if (light != null) {
light.turnOn();
}
}
}
Switch : RedLight 클래스를 직접 생성하고 사용한다.Switch 클래스가 RedLight 클래스에 의존하게 되고 만약 RED->BLUE 하려면 Switch 클래스에도 변경이 필요하다public interface Light {
void turnOn();
}
public class RedLight implements Light {
@Override
public void turnOn() {
System.out.println("Red Light turned on");
}
}
public class Switch {
private Light light;
public Switch(Light light) {
this.light= light;
}
public void flip() {
if (light!= null) {
light.turnOn();
}
}
}