...

리μ€μ½ν μΉν μμΉ - LSP (Liskov Substitution Principle)
리μ€μ½ν μΉν μμΉμ 1988λ λ°λ°λΌ 리μ€μ½ν(Barbara Liskov)κ° μ¬λ°λ₯Έ μμ κ΄κ³μ νΉμ§μ μ μνκΈ° μν΄ λ°νν κ²μΌλ‘, μλΈ νμ μ μΈμ λ κΈ°λ° νμ μΌλ‘ κ΅μ²΄ν μ μμ΄μΌ νλ€λ κ²μ λ»νλ€.
κ΅μ²΄ν μ μλ€λ λ§μ, μμ ν΄λμ€λ μ΅μν μμ μ λΆλͺ¨ ν΄λμ€μμ κ°λ₯ν νμλ μνμ΄ λ³΄μ₯λμ΄μΌ νλ€λ μλ―Έμ΄λ€.
μ¦, λΆλͺ¨ ν΄λμ€μ μΈμ€ν΄μ€λ₯Ό μ¬μ©νλ μμΉμ μμ ν΄λμ€μ μΈμ€ν΄μ€λ₯Ό λμ μ¬μ©νμ λ μ½λκ° μλ μλλλ‘ μλν΄μΌ νλ€λ μλ―Έμ΄λ€.
μ΄κ²μ λΆλͺ¨ ν΄λμ€μ μμ ν΄λμ€ μ¬μ΄μ νμκ° μΌκ΄μ±μ΄ μλ€κ³ λ§νλ€.
λ¬΄μ¨ μ¬μ€ν λ Όλ¬Έ κ°μ΄ μ€λͺ νμλλ°, κ·Έλ₯ μ°λ¦¬κ° μ§κΈκΉμ§ μλ° νλ‘κ·Έλλ°μ νλ©΄μ μ§λ¦¬λλ‘ μ¬μ©ν λ€νμ± μ리λ₯Ό μκΈ°νλ κ²μ΄λ€.
λ€νμ± κΈ°λ₯μ μ΄μ©νκΈ° μν΄μλ ν΄λμ€λ₯Ό μμ μμΌ νμ μ ν΅ν©ν μ μκ² μ€μ νκ³ , μ μΊμ€ν μ ν΄λ λ©μλ λμμ λ¬Έμ μκ² μ μ€κ³νμ¬μΌ νλ€λ κ² μ―€μ λ€λ€ μ μκ³ μμ κ²μ΄λ€.
μ΄λ¬ν LSP μμΉμ μ μ μ©ν μμ κ° μλ°μ 컬λ μ νλ μμν¬(Collection Framework) μ΄λ€.
λ§μΌ λ³μμ LinkedList μλ£νμ λ΄μ μ¬μ©νλ€, μ€κ°μ μ ν λ€λ₯Έ HashSet μλ£νμΌλ‘ λ°κΏλ add() λ©μλ λμμ 보μ₯λ°κΈ° μν΄μλ Collection μ΄λΌλ μΈν°νμ΄μ€ νμ
μΌλ‘ λ³μλ₯Ό μ μΈνμ¬ ν λΉνλ©΄ λλ€.
μλνλ©΄ μΈν°νμ΄μ€ Collectionμ μΆμ λ©μλλ₯Ό κ°κΈ° νμ μλ£ν ν΄λμ€μμ implementsνμ¬ μΈν°νμ΄μ€ ꡬν κ·μ½μ μ μ§ν€λλ‘ λ―Έλ¦¬ μ μ€κ³λμ΄ μκΈ° λλ¬Έμ΄λ€.

void myData() {
// Collection μΈν°νμ΄μ€ νμ
μΌλ‘ λ³μ μ μΈ
Collection data = new LinkedList();
data = new HashSet(); // μ€κ°μ μ ν λ€λ₯Έ μλ£ν ν΄λμ€λ₯Ό ν λΉν΄λ νΈνλ¨
modify(data); // λ©μλ μ€ν
}
void modify(Collection data){
list.add(1); // μΈν°νμ΄μ€ ꡬν κ΅¬μ‘°κ° μ μ‘νμκΈ° λλ¬Έμ add λ©μλ λμμ΄ κ°κΈ° μλ£νμ λ§κ² 보μ₯λ¨
// ...
}
λ€μνλ² λ§νμ§λ§ μ΄λ ΅κ² μκ°ν νμμμ΄, λ무λλ λΉμ°νκ² μλ°λ₯Ό μ½λ©νλ©΄μ μ¬μ©ν΄μ¨ λ€νμ±μ κ·μΉμΌλ‘μ λ¬Έμνν κ²μ΄ LSP μμΉμ΄λΌκ³ 보면 λλ€.
κ·Έλμ LSPλ νλ§λλ‘ λ€νμ±μ μ§μνκΈ° μν μμΉ μ΄λΌκ³ λ± μλΌ μ μν μ μλ€.
μ무λλ μ°λ¦¬λ μ²μ νλ‘κ·Έλλ° μΈμ΄λ₯Ό λ°°μΈλ μ½λ μ¬μ©λ²μ λ°°μ°μ§, μ½λ μ€κ³λ²μ λ°°μ°μ§ μκΈ° λλ¬Έμ μ΄λ°μμΌλ‘ λκ° νμ΅μ κ±°κΎΈλ‘ λ°°μ°λ λ―ν λλμ΄ λλκ²μ μ΄μ©μ μλ€κ³ λ³Έλ€.
LSP μμΉ μλ° μμ μ μμ νκΈ°
리μ€μ½ν μΉν μμΉμ ν΅μ¬μ λΆλͺ¨ ν΄λμ€μ νλ κ·μ½μ μμ ν΄λμ€κ° μλ°νλ©΄ μ λλ€λ κ²μ΄λ€.
νλ κ·μ½μ μλ°νλ€λ κ²μ μμ ν΄λμ€κ° μ€λ²λΌμ΄λ©μ ν λ, μλͺ»λκ² μ¬μ μνλ©΄ 리μ€μ½ν μΉν μμΉμ μλ°°ν μ μλ€λ μλ―Έμ΄λ€.
μμ ν΄λμ€κ° μ€λ²λΌμ΄λ©μ μλͺ»νλ κ²½μ°λ ν¬κ² λ κ°μ§λ‘ λλλ€.
첫λ²μ§Έλ μμ ν΄λμ€κ° λΆλͺ¨ ν΄λμ€μ λ©μλ μκ·Έλμ²λ₯Ό μκΈ° λ©λλ‘ λ³κ²½νκ±°λ, λλ²μ§Έλ μμ ν΄λμ€κ° λΆλͺ¨ ν΄λμ€μ μλμ λ€λ₯΄κ² λ©μλλ₯Ό μ€λ²λΌμ΄λ© νλ κ²½μ°κ° μλ€.
μμμ μλͺ»λ λ©μλ μ€λ²λ‘λ©
μλ μ½λ μ²λΌ Animal ν΄λμ€λ₯Ό μμνλ Eagle μμ ν΄λμ€κ° λΆλͺ¨ ν΄λμ€μ go() λ©μλλ₯Ό μκΈ° λ©λλ‘ μ½λλ₯Ό μ¬μ¬μ© νλ΅ μκ³ λ©μλ νμ
μ λ°κΎΈκ³ 맀κ°λ³μ κ°―μλ λ°κΏ λ²λ Έλ€.
νλ§λλ‘ μ΄λ λ©μλλ₯Ό μ€λ²λ‘λ©μ λΆλͺ¨κ° μλ μμ ν΄λμ€μμ ν΄λ²λ ΈκΈ° λλ¬Έμ λ°μν LSP μλ° μμΉμΈ κ²μ΄λ€.
μ΄μ°λ³΄λ©΄ λΆλͺ¨ ν΄λμ€μ νλ κ·μ½μ μ΄κΈ΄ μ μ΄λ€. κ·Έλ¦¬κ³ μ μ΄μ μ΄ μ½λλ λ€νμ± μ½λκ° λμ μμ²΄κ° λμ§ μλλ€.
class Animal {
int speed = 100;
int go(int distance) {
return speed * distance;
}
}
class Eagle extends Animal {
String go(int distance, boolean flying) {
if (flying)
return distance + "λ§νΌ λ μμ κ°μ΅λλ€.";
else
return distance + "λ§νΌ κ±Έμ΄μ κ°μ΅λλ€.";
}
}
public class Main {
public static void main(String[] args) {
Animal eagle = new Eagle();
eagle.go(10, true);
}
}

μ΄λλ κ·Έλ₯ λ©μλλ₯Ό μλ‘ λ§λ€μ΄ μ¬μ©ν λκ²μ΄ μ³λ€.
λΆλͺ¨μ μλμ λ€λ₯΄κ² λ©μλ μ€λ²λΌμ΄λ©
λ€μκ³Ό κ°μ΄ Animal ν΄λμ€μ μ΄λ₯Ό μμνλ Cat ν΄λμ€κ° μκ³ , μ΄ λλ¬Όμ΄ ν¬μ λ₯, μμ₯λ₯, νμΆ©λ₯μΈμ§ μΆλ ₯ν΄μ£Όλ NautralType ν΄λμ€κ° μλ€.
class NaturalType {
String type;
NaturalType(Animal animal) {
// μμ±μλ‘ λλ¬Ό μ΄λ¦μ΄ λ€μ΄μ€λ©΄, μ κ·ννμμΌλ‘ 맀μΉλ λλ¬Ό νμ
μ μ€μ νλ€.
if(animal instanceof Cat) {
type = "ν¬μ λ₯";
} else {
// ...
}
}
String print() {
return "μ΄ λλ¬Όμ μ’
λ₯λ " + type + " μ
λλ€.";
}
}
class Animal {
NaturalType getType() {
NaturalType n = new NaturalType(this);
return n;
}
}
class Cat extends Animal {
}
μ΄ μ½λμ μ¬μ©λ²μ μλμ κ°λ€.
λ¨Όμ Animal ν΄λμ€μ νμ₯λλ λλ¬Όλ€(Cat, Dog, Lion ...λ±)μ λ€νμ±μ μ΄μ©νμ¬ μ
μΊμ€ν
μΌλ‘ μΈμ€ν΄μ€ν ν΄μ£Όκ³ , getType() λ©μλλ₯Ό ν΅ν΄ NautralType κ°μ²΄ μΈμ€ν΄μ€λ₯Ό λ§λ€μ΄ NautralTypeμ print() λ©μλλ₯Ό μΆλ ₯νμ¬ κ°μ μ»λ ννμ΄λ€.
public class Main {
public static void main(String[] args) {
Animal cat = new Cat();
String result = cat.getType().print();
System.out.println(result); // "μ΄ λλ¬Όμ μ’
λ₯λ ν¬μ λ₯ μ
λλ€."
}
}
κ·Έλ°λ° νμ
νλ λ€λ₯Έ κ°λ°μκ° μ΄λ°μμΌλ‘ ꡬμ±νλ©΄ λκ° λ²κ±°λ‘μΈ κ² κ°μ, μκΈ° λ©λλ‘ μμ ν΄λμ€μ λΆλͺ¨ λ©μλμΈ getType() μ λ°νκ°μ nullλ‘ μ€λ²λΌμ΄λ© μ€μ νμ¬ λ©μλλ₯Ό μ¬μ©νμ§ λͺ»νκ² μ€μ νκ³ , λμ getName() μ΄λΌλ λ©μλλ₯Ό λ§λ€μ΄ νλ²μ μΆλ ₯νλλ‘ μ€μ ν κ²μ΄λ€.
class Cat extends Animal {
@Override
NaturalType getType() {
return null;
}
String getName() {
return "μ΄ λλ¬Όμ μ’
λ₯λ ν¬μ λ₯ μ
λλ€.";
}
}
κ·ΈλΌ κΈ°μ‘΄μ μ½λλ μ΄λ»κ² λ κΉ?
μ€νν΄λ³΄λ©΄ λ€μκ³Ό κ°μ΄ NullPointerException μμΈκ° λ°μνκ² λλ€.
Animal cat = new Cat();
String result = cat.getType().print();
System.out.println(result);

μ΄κ²μ΄ 리μ€μ½ν μΉν μμΉμ μ€μ ν¬μΈνΈλ€.
μμ ν΄λμ€λ‘ λΆλͺ¨ ν΄λμ€μ λ΄μ©μ μμνλλ°, κΈ°μ‘΄ μ½λμμ 보μ₯νλ 쑰건μ μμ νκ±°λ μ μ©μν€μ§ μμμ, κΈ°μ‘΄ λΆλͺ¨ ν΄λμ€λ₯Ό μ¬μ©νλ μ½λμμ μμνμ§ μμ μ€λ₯λ₯Ό λ°μμν¨ κ²μ΄λ€.
λ§μΌ μ»΄νμΌ λ¨μμ μ€λ₯λ₯Ό 체ν¬ν΄μ£Όλ©΄ μ’μν λ°, μ½λ ꡬμ±μ λ¬Έμ κ° μκΈ° λλ¬Έμ μ΄λ κ² μμΈ‘νμ§ λͺ»ν μλ¬κ° λ°μν κ²μ΄λ€.
λ°λΌμ μ¬μ μ μ½μν κΈ°νλλ‘ κ΅¬ννκ³ , μμ μ λΆλͺ¨μμ ꡬνν μμΉμ λ°λΌμΌ νλ€κ° μ΄ μμΉμ ν΅μ¬μ΄λ€.
μλͺ»λ μμ κ΄κ³ ꡬμ±μΌλ‘ μΈν λ©μλ μ μ
Animal μ΄λΌλ μΆμ ν΄λμ€λ₯Ό μ μνκ³ λλ¬Όμ λλΆλΆ λͺ©μ리λ₯Ό λΌ μ μκΈ° λλ¬Έμ μΆμ λ©μλ speak() μ ν΅νμ¬ λ©μλ ꡬνμ κ°μ νλλ‘ κ·μΉμ μ§μ νμλ€.

abstract class Animal {
void speak() {}
}
class Cat extends Animal {
void speak() {
System.out.println("λμΉ");
}
}
class Dog extends Animal {
void speak() {
System.out.println("λ©λ©");
}
}
κ·Έλ°λ° κ°λ°μ μ§ννλ€ Fish λ¬Όκ³ κΈ° ν΄λμ€λ₯Ό μΆκ°ν΄μΌ ν μν©μ΄ μμ, Animal μΆμ ν΄λμ€λ₯Ό μμνλλ, λ¬Όκ³ κΈ°λ νν μ μλ speak() λ©μλλ₯Ό ꡬνν΄μΌ νλ μν©μ΄ μ겨 λ²λ Έλ€.
λ°λΌμ κ°λ°μλ νΈνμ±μ μν΄ Fish ν΄λμ€μ speak() λ©μλλ λμμ νμ§ λͺ»νκ² νκ³ μμΈ(Exceptoin)μ λμ§λλ‘ μ€μ νμλ€.
class Fish extends Animal {
void speak() {
try {
throw new Exception("λ¬Όκ³ κΈ°λ λ§ν μ μμ");
} catch (Exception e) {
e.printStackTrace();
}
}
}
μ΄ λΆλΆμ μμ μ΄ κ°λ°νκ³ μ¬μ©νλ€ κ·Έλ¬λ©΄ λ¬Έμ κ° λμ§ μλλ€. λ¬Έμ λ λ€λ₯Έ κ°λ°μμ νμ ν λμ΄λ€.
λ§μΌ λ€λ₯Έ κ°λ°μκ° μ λλ‘λ μ€ν λ¬Έμλ₯Ό μ λ¬λ°μ§ λͺ»νκ³ λ¨μ΄ λ§λ€μ΄ λμ ν΄λμ€λ₯Ό μ¬μ©νλ €κ³ ν λ μλμ κ°μ μ½λλ₯Ό ν΅ν΄ μ λμνλ μ½λκ° κ°μκΈ° μμΈλ₯Ό λμ Έλ²λ¦΄ μ μκ² λλ€.
List<Animal> list = new ArrayList<>();
list.add(new Cat());
list.add(new Dog());
list.add(new Fish());
for(Animal a : list) {
a.speak();
}
LSP μμΉμ λ°λ₯΄λ©΄ speak() λ©μλλ₯Ό μ€ννλ©΄ κ° λλ¬Ό νμ
μ λ§κ² μΈλΆμ§λ κ²°κ³Όλ₯Ό λ΄λ³΄λ΄μΌ λλλ°, κ°μκΈ° λ¬κΈμμ΄ μμΈλ₯Ό λμ Έλ²λ¦¬λ κ°λ°μ κ° μνΈ μ λ’°λ₯Ό μκ² λ μλ μλ€.
μ΄μ²λΌ 리μ€μ½ν μΉν μμΉμ νμ νλ κ°λ°μ μ¬μ΄μ μ λ’°λ₯Ό μν μμΉμ΄κΈ°λ νλ€.
λ°λΌμ μ½λλ₯Ό μμ νλ€λ©΄ λ°λ‘ μΈν°νμ΄μ€λ‘ λΉΌλ μμ μ ν΅ν΄ μμ μ ν΄μΌ νλ€.

abstract class Animal {
}
interface Speakable {
void speak();
}
class Cat extends Animal implements Speakable {
public void speak() {
System.out.println("λμΉ");
}
}
class dog extends Animal implements Speakable {
public void speak() {
System.out.println("λ©λ©");
}
}
class Fish extends Animal {
}
LSP μμΉ μ μ© μ£Όμμ
κ²°κ΅ λ¦¬μ€μ½ν μΉν μμΉμ΄λ, λ€νμ±μ νΉμ§μ μ΄μ©νκΈ° μν΄ μμ ν΄λμ€ νμ μΌλ‘ κ°μ²΄λ₯Ό μ μΈνμ¬ νμ ν΄λμ€μ μΈμ€ν΄μ€λ₯Ό λ°μΌλ©΄, μ μΊμ€ν λ μνμμ λΆλͺ¨μ λ©μλλ₯Ό μ¬μ©ν΄λ λμμ΄ μλλλ‘λ§ νλ¬κ°λλ‘ κ΅¬μ±νλ©΄ λλ κ²μ΄λ€.
κ·Έλ¦¬κ³ LSP μμΉμ ν΅μ¬μ μμ(Inheritance)μ΄λ€.
κ·Έλ°λ° μ£Όμν μ μ, κ°μ²΄ μ§ν₯ νλ‘κ·Έλλ°μμ μμμ κΈ°λ° ν΄λμ€μ μλΈ ν΄λμ€ μ¬μ΄μ IS-A κ΄κ³κ° μμ κ²½μ°λ‘λ§ μ ν λμ΄μΌ νλ€.
κ·Έ μΈμ κ²½μ°μλ ν©μ±(composition)μ μ΄μ©νλλ‘ κΆκ³ λμ΄ μλ€.
λ°λΌμ λ€νμ±μ μ΄μ©νκ³ μΆλ€λ©΄ extends λμ μΈν°νμ΄μ€λ‘ implementsνμ¬ μΈν°νμ΄μ€ νμ
μΌλ‘ μ¬μ©νκΈ°λ₯Ό κΆνλ©°, μμ ν΄λμ€μ κΈ°λ₯μ μ΄μ©νκ±°λ μ¬μ¬μ©μ νκ³ μΆλ€λ©΄ μμ(inheritnace) λ³΄λ¨ ν©μ±(composition)μΌλ‘ ꡬμ±νκΈ°λ₯Ό κΆμ₯νλ€.
# μ°Έκ³ μλ£
https://www.nextree.co.kr/p6960/
https://www.youtube.com/watch?v=btjntkW_rAE
https://youtu.be/_G50Joyys_E
https://ehpub.co.kr/java-%ED%99%9C%EC%9A%A9-3-3-collection-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4/
μ΄ κΈμ΄ μ’μΌμ ¨λ€λ©΄ ꡬλ & μ’μμ
μ¬λ¬λΆμ ꡬλ
κ³Ό μ’μμλ
μ μμκ² ν° νμ΄ λ©λλ€.