두 번의 과제를 진행하며 매번 들었던 피드백이 있다.
설계를 할 때 요구사항을 정리해 행위만 분류한다. 이는 함수가 될 수 있고, 비슷한 성격의 함수를 모아 클래스를 만들 수 있다.
바로 클래스, 메서드를 확실하게 분리해서 좀 더 직관적이고 보기 쉬운 코드를 만들자! 라는 내용이였다.
.
.
.
그런데,
어떤 기준으로 분리하고 설계를 해야할까? 를 고민하다가 객체지향 설계원칙인 SOLID 원칙 을 알게 되어 소개한다.
각 원칙을 예시와 함께 살펴보자.
User 클래스가 회원 정보를 관리하고, UserAuthenticator 클래스는 로그인 기능만 담당하게 한다. 이는 클래스가 하나의 역할만 수행하도록 하여 유지보수를 쉽게 한다.public class User {
private String name;
private String email;
// Getter, Setter
}
public class UserAuthenticator {
public boolean login(String email, String password) {
return true;
}
}
Shape 인터페이스를 통해 새로운 도형 클래스가 추가될 때 기존 코드를 수정하지 않고도 기능을 확장할 수 있다.public interface Shape {
double area();
}
public class Rectangle implements Shape {
private double width, height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
public double area() {
return width * height;
}
}
Bird 클래스와 Penguin 클래스에서 Penguin은 fly() 대신 move()를 통해 LSP를 준수하게 한다.public abstract class Bird {
public abstract void move();
}
public class Sparrow extends Bird {
public void move() {
System.out.println("날고 있다!");
}
}
public class Penguin extends Bird {
public void move() {
System.out.println("걷고 있다!");
}
}
Worker 인터페이스를 분리해 Work와 Eat 인터페이스로 분리해 필요한 기능만 구현하게 한다.public interface Work {
void work();
}
public interface Eat {
void eat();
}
public class Worker implements Work {
public void work() {
System.out.println("일하고 있다!");
}
}
MessageSender 인터페이스를 통해 NotificationService가 EmailSender나 SMSSender에 직접 의존하지 않도록 한다.public interface MessageSender {
void sendMessage(String message);
}
public class EmailSender implements MessageSender {
public void sendMessage(String message) {
System.out.println("이메일 발송: " + message);
}
}
public class NotificationService {
private MessageSender messageSender;
public NotificationService(MessageSender messageSender) {
this.messageSender = messageSender;
}
public void notify(String message) {
messageSender.sendMessage(message);
}
}
SOLID 원칙을 준수하면 코드의 유연성과 유지보수성이 높아지고, 변화에 강한 구조를 만들 수 있다.