개발관련 책

면접을 위한 CS 전공지식 노트 1장

MIN우 2024. 3. 24. 18:19
728x90

디자인 패턴과 프로그래밍 패러다임

 

라이브러리 - 공통으로 사용될 수 있는 특정한 기능들을 모듈화한 것을 의미한다.

프레임워크에 비해 자유롭다.

 

프레임워크 - 공통으로 사용될 수 있는 특정한 기능들을 모듈화한 것을 의미한다.폴더명,파림여 등에 대한 규칙이 있으며 라이브러리에 비해 좀 더 엄격하다.

 

디자인 패턴이란?

- 프로그램을 설계할 때 발생했던 문제점들을 객체 간의 상호관계 등의 이용하여 해결할 수 있도록 하나의 "규약"

형태로 만들어놓은 것 입니다.

 

1. 싱글톤 패턴

 

- 하나의 클래스에 오직 하나의 인스턴스만 가지는 패턴, 하나의 클래스를 기반을 여러개의 개별적인 인스턴스를 만들 수 있지만, 그렇지게하지않고 하나의 클래스를 기반으로 단 하나의 인스턴스를 만들어 이를 기반으로 로직을 만드는데 쓰이며 ,브통 데이터베이스 연결모듈에 많이사용합니다.

 

장점: 하나의 인스턴스를 만들어 놓고 해당 인스턴스를 다른 모듈들이 공유하며 사용하기 때문에 인스턴스를 생성할 때 드는 비용이 줄어드는 장점이 있다.

단점: 의존성이 높아진다, TDD를 할 때 걸림돌이 된다. TDD를할 때 단위테스트를 주로 하는데, 단위테스트는 테스트가 서로 독립적이여야하며 어떤 순서로든 실행할 수 있어야한다. 하지만 싱글톤 패턴은 미리 생성된 하나의 인스턴스를 기반으로 구현하는 패턴이므로 각 테스트마다 독립적인 인스턴스를 만들기가 어렵다.

 

싱글톤 패턴 - 예제

 

 

 

2. 팩토리 패턴

객체를 사용하는 코드에서 객체 생성 부분을 떼어내 추상화한 패턴이자 상속 관계에 있는 두 클래스에서 상위 클래스가 중요한 뼈대를 결정하고, 하위 클래스에서 객체 생성에 관한 구체적인 내용을 결정하는 패턴. 상위클래스와 하위클래스가 분리되기 때문에 느슨한 결합을 가지며 상위 클래스에서는 인스턴스 생성 방식에 대해 전혀 알 필요가 없기 떄문에 더 많은 유연성을 가진다. 또한 객체 생성 로직이 따로 뗴어져 있기 떄문에 코드를 리팩토링하더라도 한 곳만 고칠 수 있게 되니 유지 보수성이 증가됩니다.

 

  • Instnce 작성을 하위 class에게 위임
    • Instance를 만드는 방법은 상위 class에서 결정하지만, 구체적인 class명을 결정하지 않음
  • Instance 생성을 위한 Framework과 실제 Instance를 생성하는 Class를 분리함
  • 객체를 만드는 공장을 만드는 패턴 -> 결합도가 낮아질 수 있다

 

팩토리패턴 - 예제

enum CoffeeType {
    LATTE,
    ESPRESSO
}

abstract class Coffee {
    protected String name;

    public String getName() {
        return name;
    }
}

class Latte extends Coffee {
    public Latte() {
        name = "latte";
    }
}

class Espresso extends Coffee {
    public Espresso() {
        name = "Espresso";
    }
}

class CoffeeFactory {
    public static Coffee createCoffee(CoffeeType type) {
        switch (type) {
            case LATTE:
                return new Latte();
            case ESPRESSO:
                return new Espresso();
            default:
                throw new IllegalArgumentException("Invalid coffee type: " + type);
        }
    }
}

public class Main {
    public static void main(String[] args) { 
        Coffee coffee = CoffeeFactory.createCoffee(CoffeeType.LATTE); 
        System.out.println(coffee.getName()); // latte
    }
}

 

Enum: 상수의 집합을 정의할 때 사용한다. 상수 집합을 관리하면 코드를 리팩터링할 때 상수 집합에 대한 로직 수정 시 이 부분만 수정하면 된다는 장점이 있다. 본절적으로는 thread safe 하기때문에 싱글톤 패턴을 만들 때 도움이 된다.

 

 

 enum은 자동으로 synchronized하게 생성되므로 thread safe하다.

 

3. 전략 패턴

전략패턴은 정책패턴이라고도 하며 , 객체의 행위를 바꾸고 싶은 경우 "직접" 수정하지않고 전략이라고 부르는 캡슐화한 알고리즘을 컨텍스트 안에서 바꿔주면서 상호교체가 가능하게 만드는 패턴

즉 , 변경시 대응에 용이하도록 변경이 잦은 행위를 추상화하는 것 ex ) 결제전략 시 kakopay ,naverpay 등등 ?

 

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
interface PaymentStrategy { 
    public void pay(int amount);
} 

class KAKAOCardStrategy implements PaymentStrategy {
    private String name;
    private String cardNumber;
    private String cvv;
    private String dateOfExpiry;
    
    public KAKAOCardStrategy(String nm, String ccNum, String cvv, String expiryDate){
        this.name=nm;
        this.cardNumber=ccNum;
        this.cvv=cvv;
        this.dateOfExpiry=expiryDate;
    }

    @Override
    public void pay(int amount) {
        System.out.println(amount +" paid using KAKAOCard.");
    }
} 

class LUNACardStrategy implements PaymentStrategy {
    private String emailId;
    private String password;
    
    public LUNACardStrategy(String email, String pwd){
        this.emailId=email;
        this.password=pwd;
    }
    
    @Override
    public void pay(int amount) {
        System.out.println(amount + " paid using LUNACard.");
    }
} 

class Item { 
    private String name;
    private int price; 
    public Item(String name, int cost){
        this.name=name;
        this.price=cost;
    }

    public String getName() {
        return name;
    }

    public int getPrice() {
        return price;
    }
} 

class ShoppingCart { 
    List<Item> items;
    
    public ShoppingCart(){
        this.items=new ArrayList<Item>();
    }
    
    public void addItem(Item item){
        this.items.add(item);
    }
    
    public void removeItem(Item item){
        this.items.remove(item);
    }
    
    public int calculateTotal(){
        int sum = 0;
        for(Item item : items){
            sum += item.getPrice();
        }
        return sum;
    }
    
    public void pay(PaymentStrategy paymentMethod){
        int amount = calculateTotal();
        paymentMethod.pay(amount);
    }
}  

public class HelloWorld{
    public static void main(String []args){
        ShoppingCart cart = new ShoppingCart();
        
        Item A = new Item("kundolA",100);
        Item B = new Item("kundolB",300);
        
        cart.addItem(A);
        cart.addItem(B);
        
        // pay by LUNACard
        cart.pay(new LUNACardStrategy("kundol@example.com", "pukubababo"));
        // pay by KAKAOBank
        cart.pay(new KAKAOCardStrategy("Ju hongchul", "123456789", "123", "12/01"));
    }
}
/*
400 paid using LUNACard.
400 paid using KAKAOCard.
*/

 

4. 옵저버 패턴

옵저버 패턴은 주체가 어떤 객체의 상태 변화를 관찰하다가 상태 변화가 있을때마다 메서드 등을 통해 옵저버 목록에 있는 

옵저버들에게 변화를 알려주는 디자인패턴

여기서 주체란 객체의 상태변화를 보고 있는 관찰자이며, 옵저버들이란 이 객체의 상태 변화에 따라 전달되는 메서드 등을 기반으로 "추가  변화 사항"이 생기는 객체들을 의미합니다.

 

옵저버패턴은 주로 이벤트 기반 시스템에 사용하며 MVC패턴에도 사용됩니다. 

ex) 주체라고 볼 수 있는 모델에서 변경 사항이 생겨 update() 메서드로 옵저버인 뷰에 알려주고 이를 기반으로 controller 등이 작동하는 것이죠.

 

 

여기서 상속과, 구현의 차이를 짚고 가겠습니다.

 

상속- extends은 자식클래스가 부모 클래스의 메서드 등을 상속받아 사용하며 자식 클래스에서 추가 및 확장할 수 있는 것을 말합니다. 이로 인해 재사용성 , 중복성의 최소화가 이루어집니다.

 

구현- 부모 인터페이스를 자식 클래스에서 재정의하여 구현하는 것을 말하며, 상속과는 달리 반드시 부모 클래스의 메서드를 재정의하여 구현해야 합니다.

 

5.프록시 패턴

 

프록시 패턴은 대상 객체에 접근하기 전 그 접근에 대한 흐름을 가로채 해당 접근을 필터링하거나 수정하는 등의 역할을 하는 계층이 있는 디자인 패턴입니다.

 

이를 통해 객체의 속성 ,변환 등을 보완하며 보안,데이터 검증, 캐싱,로깅에 사용합니다. 이는 앞서 설명한 프록시 객체로 쓰이기도 하지만 프록시 서버로도 활용됩니다.

 

프록시 서버에서의 캐싱

캐시 안에 정보를 담아두고, 캐시 안에 있는 정보를 요구하는 요청에 대해 다시 저 멀리 있는 원격 서버에 요청하지 않고 캐시 안에 있는 데이터를 활용하는 것을 말한다. 이를 통해 불필요하게 외부와 연결하지 않기 때문에 트래픽을 줄일 수 있다는 장점이 있다.

 

프록시서버 - 웹서버를 사용하게 되면 장점이 무엇이 있을까 ?

 

1. End Point

Forward Proxy 는 클라이언트가 요청하는 End Point 가 실제 서버 도메인이고 프록시는 둘 사이의 통신을 담당해준다.

Reverse Proxy 는 클라이언트가 요청하는 End Point 가 프록시 서버의 도메인이고 실제 서버의 정보는 알 수 없다.

2. 감춰지는 대상

Forward Proxy 는 클라이언트가 감춰진다.

요청 받는 서버는 포워드 프록시 서버를 통해서 요청을 받기 때문에 클라이언트의 정보를 알 수 없다.

Reverse Proxy 는 반대로 서버가 감춰진다.

클라이언트는 리버스 프록시 서버에게 요청하기 때문에 실제 서버의 정보를 알 수가 없다.

NGINX 기능

  • 웹 서버
  • 로드 밸런서
  • 웹 서버 가속기
  • SSL 터미네이션 : 클라이언트와 https 통신하고, 서버와 http 통신하는 것
  • 캐싱 : http 프로토콜을 사용하여 전달하는 콘텐츠를 캐싱할 수 있음, 한 번 서버에서 응답받은 것을 스스로 보관하고 클라이언트에 전달함.
  • HSTS(HTTP Strict Transport Security)
  • CORS 처리
  • TCP/UDP 커넥션 부하 분산
  • HTTP/2 등
  • 서버 앞단에 둬서 버퍼 오버플로우를 해겨할 수 있습니다.

성능테스트를 진행할 경우에는 http로 설정해야한다. 그래야 정확한 tps를 알 수 있다.

 

1. HTTPS구축 : 서버에서 HTTPS를 구축할 때 인증서를 기반으로 구축할 수도 있습ㄴ디 .

2. DDOS공격 방어: DDOS 짧은 기간 동안 네트워크에 많은 요청을 보내 네트워크를 마비시켜 웹 사이트의 가용성을 방해하는 사이버 공격유형. 네트워크 용량 및 캐싱을으로 DDOS를 막을 수 있다.

 

 

CDN이란 ? 

각 사용자가 인터넷에 접속하는 곳과 가까운 곳에서 콘텐츠를 캐싱 또는 배포하는 서버 네트워크를 말한다. 이를 통해 사용자가 웹 서버로부터 콘텐츠를 다운로드하는 시간을 줄일 수 있다.

엣지 로케이션이라고도 한다.

 

CORS란 ?

서버가 웹 브라우저에서 리소스를 로드할 때 다른 오리진을 통해 로드하지 못하게 하는 HTTP 헤더 기반 매커니즘이다.

 

오리진이란 ?

프로토콜과 호스트이름 , 포트의 조합을 말한다. 예를들어 https://flowbit.co.kr:8080/test 라는 주소에서 오리진은 https://flowbit.co.kr:8080을 을 뜻한다

 

6. 이터레이터 패턴

이터레이터 패턴은 이터레이터를 사용하여 컬렉션의 요소들에 접근하는 디자인패턴입니다. 이를 통해 순회할 수 있는 여러가지 자료형의 구조와는 상관ㅇ벗이 이터레이터라는 하나의 인터페이스로 순회가 가능합니다.

 

분명히 다른 자료 구조인 set과 map임에도 불구하고 for a of b라는 이터레이터 프로토콜을 통해 순회할 수 있다.

 

Iterator 패턴을 적용하면 어떤 장점이 있을까?

for문으로 동일한 표현이 가능한데 왜 굳이 코드를 늘려가며 Iterator 패턴을 사용해야 하는지 의문이 들 수 있다.

Iterator 패턴을 사용하는 가장 큰 이유는 하나씩 꺼내서 처리하는 과정을 구현과 분리할 수 있기 때문이다.

다음의 코드를 살펴보자.

 

1) Iterator 패턴을 사용했을 때

while (it.hasNext()) {
    Book book = (Book) it.next();
    System.out.println(book.getName());
}

 

2) for문을 사용했을 때

for (int i = 0; i < bookShelf.getLength(); i++) {
    System.out.println(bookShelf.getBook(i).getName());
}

이 두가지 코드는 실행 시 Book 객체의 내용을 하나씩 꺼내서 보여주는 동일한 결과를 보여준다.

하지만 for문을 사용할 때와 달리 Iterator 패턴을 사용할 때는 어디까지나 Iterator의 메서드를 사용할 뿐 BookShelf의 구현에서 사용되고 있는 메서드는 호출되지 않고있다.

 

즉, 1번 방식은 BookShelf의 구현에 의존하지 않는다.

BookShelf에 무언가 수정사항이 생기더라도 BookShelf가 올바른 Iterator를 반환하기만 한다면 while문이 사용되는 Main은 수정할 필요가 없다. 하나의 클래스를 수정하더라도 다른 클래스에 큰 영향 없이 작은 수정 만으로도 끝낼 수 있다는 것이다.

 

요약

  • Iterator 패턴은 집합체의 요소를 순서대로 지정하면서 처리하는 방식
  • Iterator(반복자) : 요소를 순서대로 검색하는 인터페이스를 결정
  • ConcreteIterator(구체적인 반복자) : Iterator가 결정한 인터페이스를 실제로 구현한다. 검색하기 위해 필요한 정보를 가지고 있어야 한다.
  • Aggregate(집합체) : Iterator 역할을 만드는 인터페이스를 결정한다.
  • ConcreteAggregate(구체적인 집합체) : Aggregate 역할이 결정한 인터페이스를 실제로 구현한다.

 

이를 클래스 다이어그램으로 표기하면 아래와 같다.

출처 : GoF 디자인 패턴

 

7.노출모듈패턴

노출모듈패턴은 즉시 실행 함수를 통해 private,public같은 접근 제어자를 만드는 패턴을 말합니다. 

 

 

8. MVC패턴

MVC패턴은 모델 뷰 컨트롤러로 이루어진 디자인패턴입니다.

 

애플리케이션의 구성요소를 세 가지 역할로 구분하여 개발 프로세스에서 각각의 구성 요소에만 집중해서 개발할 수 있습니다. 재사용성과 확장성이 용이하다는 장점이 있고, 애플리케이션이 복잡해질수록 모델과 뷰의 관계가 복잡해지는 단점이 있습니다.

 

모델

model은 애플리케이션의 데이터인 데이터베이스,상수,변수 등을 뜻합니다.

 

 

뷰는 inpubox,checkbox,textarea 등 사용자 인터페이스 요소를 나타냅니다. 즉 , 모델을 기반으로 사용자가 볼 수 있는 화면을 뜻합니다. 변경이 일어나면 컨트롤러에 이를 전달해야합니다.

 

컨트롤러

 

컨트롤러는 하나 이상의 모델과 하나 이상의 뷰를 잇는 다리 역할을 하며 이벤트 등 메인 로직을 담당ㅎ랍니다. 또한 모델과 뷰의 생명주기도 관리하며, 모델이나 뷰의 변경 통지를 받으면 이를 해석하여 각각의 구성 요소에 해당 내용에 대해 알려줍니다.

 

9. MVP패턴 

컨트롤러가 presenter로 교체된 패턴

뷰와 프레젠터는 일대일 관계이기 때문에 MVC 패턴보다 더 강한 결합을 지닌 디자인 패턴이라고 볼 수 있습니다.

 

10.MVVM패턴

MVVM패턴은 MVC의 C에 해당하는 컨트롤라가 뷰 뷰모델로 바뀐 패턴입니다.

 

여기서 뷰모델은 뷰를 더 추상화한 계층이며, MVVM패턴은 MVC패턴과는 다르게 커맨드와 데이터 바인딩을 가지는 것이 특징입니다. 뷰와 뷰모델 사이에 양방향 데이터 바인딩을 지원하며 UI를 별도의 코드 수정없이 재사용할 수 있고 단위테스팅하기 쉽다는 장점이 있습니다. 뷰 모델은 뷰를 추상화한 개념이빈다. MVVM은 데이터를 바인딩하여 가지고 있기 떄문에 뷰와 뷰모델 사이의 양방향 데이터 바인딩을 지원하여 UI를 별도의 코드 수정 없이 재사용할 수 있고 단위테스트하기 쉽다.

 

프로그래밍 패러다임

 

 

함수형 프로그래밍은 : 작은 "순수 함수:들을 블록처럼 쌓아 로직을 구현하고 "고차 함수"를 통해 재사용성을 높인 프로그래밍 패러다임입니다. 함수가 일급객체이기 때문에 객체지향프로그래밍보다는 함수형 프로그래밍 방식이 선호된다.

 

순수함수란 ? 출력이 입력에만 의존하는 것을 의미합니다.

 

고차함수란 ? 함수가 함수를 값처럼 매개변수로 받아 로직을 생성할 수 있는 것을 의미합니다.

 

일급객체란 ? 

이떄 고차함수를 쓰기 위해서는 해당 언어가 일급객체라는 특징을 가져야합니다.

 

- 변수나 메소드에 함수를 할당할 수 있어야합니다.

- 함수 안에 함수를 매개변수로 담을 수 있습니다.

- 함수가 함수를 반화할 수 있습니다.

 

참고로 함수형 프로그래밍은 이외에도 커링,불변성 등 많은 특징이 있습니다.

 

  1. 불변성 (Immutability): 함수형 프로그래밍은 데이터의 불변성을 강조한다. 이는 데이터가 한 번 생성되면 변경되지 않는다는 것을 의미한다. 불변성은 코드의 복잡성을 줄이고, 사이드 이펙트(side effects)를 방지하며, 프로그램의 예측 가능성을 향상시킨다.
  2. 함수의 일급 객체 (First-Class Functions): 함수형 프로그래밍에서 함수는 "일급 객체"이다. 이는 함수를 변수에 할당하거나, 다른 함수의 인자로 전달하거나, 함수에서 함수를 반환할 수 있음을 의미한다. 이러한 특성으로 인해 고차 함수를 사용할 수 있게 된다.
  3. 고차 함수 (Higher-Order Functions): 고차 함수는 다른 함수를 인자로 받거나 함수를 결과로 반환하는 함수이다. 이들은 코드의 재사용성을 높이고, 추상화 수준을 끌어올려 더 간결하고 읽기 쉬운 코드를 작성할 수 있게 한다.
  4. 사이드 이펙트 감소: 함수형 프로그래밍은 순수 함수(pure functions) 개념을 사용한다. 순수 함수는 같은 입력에 대해 항상 같은 출력을 반환하며, 외부 상태를 변경하지 않는다. 이는 프로그램의 동작을 이해하고 예측하기 쉽게 만든다.
  5. 모듈성 (Modularity): 함수형 코드는 일반적으로 더 모듈화되어 있다. 작은 함수로 분리되어 있기 때문에 각 함수를 독립적으로 테스트하고 재사용하기가 쉽다.
  6. 병렬 처리 (Parallelism): 불변성과 순수 함수는 병렬 코드를 작성할 때 발생할 수 있는 문제를 줄여준다. 공유 상태를 변경하지 않기 때문에 데이터 경쟁(data race)이 발생할 가능성이 적어진다.
  7. 더 나은 추상화: 고차 함수를 사용하는 함수형 프로그래밍은 개발자가 보다 높은 수준의 추상화에 집중할 수 있게 해준다. 예를 들어, map, filter, reduce 같은 함수들은 데이터를 처리하는 복잡한 로직을 간단한 함수 호출로 대체할 수 있게 해준다.

 

일급 객체는 뭐임?

  1. 변수에 할당될 수 있다: 변수에 할당하고 다른 변수처럼 조작할 수 있다.
  2. 다른 함수의 인자로 전달될 수 있다: 다른 함수에 인자로 넘길 수 있습니다. 이는 고차 함수를 가능하게 합니다.
  3. 다른 함수의 결과로 반환될 수 있다: 다른 함수의 반환값으로 사용될 수 있습니다.
  4. 익명으로 생성될 수 있다: 익명 함수(또는 람다)를 사용하여 이름이 없는 함수를 만들 수 있다.

그렇다면 꼭 병렬처리가 되는 stream이 for문보다 빠를까 ? 다음 커뮤니티를 참고하자...! 결론 -> 케바케

https://okky.kr/questions/1390568

 

OKKY - 자바 stream 사용 시 병렬처리와 순차처리 속도 비교 질문이요..

제가 자바 stream을 사용할 때병렬처리 ( stream().parallel() ) 을 사용할 때와병렬처리 안하고 그냥 stream()을 사용할 때 (이러면 순차처리가 맞죠?)실행 시간 비교를 하려고 합니다..제가 알기론 병렬처

okky.kr

 

객체지향 프로그래밍

객체지향 프로그래밍은 OOP로 객체들의 집합으로 프로그램의 상호 작용을 표현하며 데이터를 객체로 취급하여 객체 내부에 선언된 메서드를 활용하는 방식을 말합니다. 설계에 많은 시간이 소요되며 처리 속도가 다른 프로그래밍 패러다임에 비해 상대적으로 느립니다.

 

객체지향 프로그래밍의 특징

 

추상화: 복잡한 시스템으로부터 핵심적인 개념 또는 기능을 간추려내는 것을 의미합니다. 

 

캡슐화: 객체의 속성과 메서드를 하나로 묶고 일부를 외부에 감추어 은닉하는 것을 말합니다.

 

상속성: 상위 클래스의 특성을 하위 클래스가 이어받아서 재사용하거나 추가,확장하는 것을 말합니다.

코드의 재사용 측면, 계층적인 관계 생성, 유지 보수성 측면에서 중요합니다.

 

다형성: 하나의 메서드나 클래스가 다양한 방법으로 동작하는 것을 말합니다. 대표적으로는 오버로딩, 오버라이딩이 있습니다.

 

- 오버로딩: 같은 이름을 가진 메서드를 여러 개 두는 것을 말합니다. 메서드의 타입,매개변수의 유형, 개수 등으로 여러개를 둘 수 있으며 컴파일 중에 발생하는 정적 다형성입니다.

 

- 오버라이딩: 주로 메서드 오버라이딩을 말하며 상위클래스로부터 상속받은 메소드를 하위 클래스가 재정의하는 것을 의미합니다. 동적 다형성이라고 합니다

 

설계원칙

 

SOLID원칙

 

SRP: 단일책임원칙

- 모든 클래스는 각각 하나의 책임만 가져야하는 원칙입니다. ex ) A라는 로직이 존재한다면 어떠한 클래스는 A에 관한 클래스여야 하고 이를 수정한다고 했을 때도 A와 관련된 수정이어야 합니다.

 

OCP: 개방폐쇠원칙

- 유지보수 사항이 생긴다면 코드를 쉽게 확장할 수 있도록 하고 수정할 떄는 닫혀 있어야하는 원칙입니다.

즉, 기존의 코드는 잘 변경하지 않으면서도 확장은 쉽게할 수 있어야합니다.

 

LSP:리스코프치환원칙

- 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위타입의 인스턴스로 바꿀 수 있어야 하는 것을 의미합니다.즉, 범석객체가 홍철객체의 자식 계층일 때 범석 객체를 홍철 객체와 바꿔도 문제가 없어야합니다. 부모객체에 자식 객체를 넣어도 시스템이 문제 없이 돌아가야 한다.

 

ISP: 인터페이스 분리원칙

하나의 일반적인 인터페이스보다 구체적인 여러개의 인터페이스를 만들어야하는 원칙 입니다.

 

DIP: 의존 역전 법칙

자신보다 변하기 쉬운 것에 의존하는 것을 추상화 인터페이스나 상위 클래스를 두어 변하기 쉬운 것의 영향을 받지 않게 하는 원칙입니다. 예를 들어 타이어를 갈아 끼울 수 있는 틀을 만들어 놓은 후 다양한 타이어를 교체할 수 있어야합니다. 즉 , 상위 계층은 하위 계층의 변화에 대한 구현으로부터 독립해야합니다.

 

 

 

 

 

 

728x90