공부/SOLID
Liskov Substitution Principle(리스코프 치환 원칙 )
ironk.im
2021. 6. 1. 23:21
반응형
Liskov Substitution Principle은 서브타입이 부모타입으로 대체될 수 있어야 한다는 것이다.
이렇게 보면 이해하기가 조금 난해할 수 있다.
간단히 설명하면 상속 또는 인터페이스를 구현하는 어떤 클래스가 상위 클래스에 대체될 수 있어야하고, 그 때 일관된 동작을 보장해야한다는 것이다.
즉, 일관성과 안정성을 보장해야한다는 원칙이다.
Liskov Substitution Principle을 준수하지 않는 코드
public class Bird {
public void fly() {
System.out.println("fly high!");
}
}
public class Penguin extends Bird {
@Override
public void fly() {
throw new IllegalStateException("I can not fly!");
}
}
public class Zoo {
public static void main(String[] args) {
System.out.println("새들이 나는 공연");
List<Bird> birds = new ArrayList<>();
birds.add(new Bird());
birds.add(new Penguin());
birds.forEach(Bird::fly);
}
}
Liskov Substitution 원칙을 준수 하지 않은 코드를 보면 Bird를 보면 해당 클래스는 fly라는 메소드가 있고 하늘을 나는 기능을 수행하는 메소드임을 알 수 있다.
그러나 Bird를 상속하는 자식 클래스인 Penguin은 Bird를 상속하고 있어 fly 메소드가 있어 하늘을 나는 기능을 수행할 것이라고 예상되나 Penguin은 하늘을 날 수 없다.
이러한 경우 Penguin은 부모 클래스인 Bird를 상속 하였지만 Bird클래스를 대체하여 일관적인 기능(fly)를 제공할 수 없다.
Bird를 사용하는 부분이 Penguin으로 대체 되어도 정상 동작 되어야하나 Penguin은 날지 못하기 때문에 이러한 기능을 제공할 수 없다
Liskov Substitution Principle을 준수하는 코드
public interface Flyable {
void fly();
}
public class Bird {
public void sing() {
System.out.println("Singing");
}
}
public class Magpie extends Bird implements Flyable {
@Override
public void fly() {
System.out.println("I can fly!");
}
}
public class Penguin extends Bird {
}
public class Zoo {
public static void main(String[] args) {
System.out.println("새들이 나는 공연");
List<Bird> allBirds = List.of(new Magpie(), new Penguin());
System.out.println("새들 노래");
allBirds.forEach(Bird::sing);
System.out.println("날 수 있는 새들 공연");
allBirds.stream()
.filter(b -> b instanceof Flyable)
.map(b -> (Flyable) b)
.forEach(Flyable::fly);
}
}
Flyable 인터페이스로 fly기능을 분리하고 fly가 필요한 경우 해당 기능을 구현하도록 함으로서 Liskov Substitution Principle을 준수하였다고 볼 수 있다.
리스코프 치환 원칙에서 중요한 부분은 일관된 동작을 보장해야 한다는 부분이라고 생각한다.
반응형