기술 블로그

[CS] 디자인패턴 본문

카테고리 없음

[CS] 디자인패턴

jaegwan 2023. 11. 11. 00:04
반응형

1. 디자인패턴

라이브러리/프레임워크: 공통으로 사용될 수 있는 특정 기능을 모듈화한 것

디자인 패턴: 프로그램설계시 문제발생을 예방하고 객체 간 상호 관계를 이용해 해결할 수 있도록 한 규약

싱글톤 패턴

하나의 클래스에 하나의 인스턴스만 가지는 패턴

특징

  • 데이터베이스 연결 모듈에 자주 사용
  • 인스턴스를 공유하여 인스턴스 생성 비용 감소

단점

  • 의존성이 높아짐
    • 의존성:소프트웨어 개발에서 한 요소나 모듈이 다른 요소나 모듈에 어떻게 의존하고 있는지를 나타내는 개념
    • 다른 클래스나 모듈에서 해당 싱글톤 인스턴스에 접근할 수 있고 이로인해 코드가 더 긴밀히 결합되어 하나의 클래스나 모듈이 변경되면 다른 클래스나 모듈도 영향을 받을 수 있음
      • 이는 유지보수와 확장성 측면에서 문제을 일으킬 수 있음
    → 그러나 의존성 주입을 통해 강한 의존성을 완화(디커플링) 할 수 있음
    • 메인 모듈이 아닌 의존성 주입자를 통해 하위 묘둘에 간접적으로 의존성을 주입
      • 의존성 주입 장점
        • 모듈을 쉽게 교체할 수 있어 테스팅과 마이그레이션에 유리
        • 추상화 레이어를 통해 의존성 방향이 일관되고 쉽게 추론하며 모듈 간 관계가 명확해짐
      • 의존성 주입 단점
        • 모듈의 분리로 클래스 수가 늘어나 복잡성 증가 가능성
        • 런타임 패널티 증가
  • TDD 단위테스트에 비적합
    • 독립적이지 못한 인스턴스 때문
class Singleton {
    constructor() {
        if (!Singleton.instance) { //싱글톤 인스턴스가 없다면
            Singleton.instance = this // 이 인스턴스가 싱글톤 인스턴스다.
        }
        return Singleton.instance //객체가 반환되었으므로 해당 객체가 인스턴스로 반환됨
    }
    getInstance() { // ge
        return this 
    }
}
const a = new Singleton()
const b = new Singleton() 
console.log(a === b) // true
const URL = 'mongodb://localhost:27017/kundolapp' 
const createConnection = url => ({"url" : url})    
class DB {
    constructor(url) {
        if (!DB.instance) { 
            DB.instance = createConnection(url)
        }
        return DB.instance
    }
    connect() {
        return this.instance
    }
}
const a = new DB(URL)
const b = new DB(URL) 
console.log(a === b) // true

팩토리 패턴

객체 생성부분을 추상화하고 상위 클래스와 하위 클래스의 역할을 구분

class CoffeeFactory { // 상위 클래스 
    static createCoffee(type) {
        const factory = factoryList[type]
        return factory.createCoffee()
    }
}   
class Latte {
    constructor() {
        this.name = "latte"
    }
}
class Espresso {
    constructor() {
        this.name = "Espresso"
    }
} 

class LatteFactory extends CoffeeFactory{ //하위클래스
    static createCoffee() {
        return new Latte()
    }
}
class EspressoFactory extends CoffeeFactory{//하위클래스 
    static createCoffee() {
        return new Espresso()
    }
}
const factoryList = { LatteFactory, EspressoFactory } 
 
 
const main = () => {
    // 라떼 커피를 주문한다.  
    const coffee = CoffeeFactory.createCoffee("LatteFactory")  
    // 커피 이름을 부른다.  
    console.log(coffee.name) // latte
}
main()
  • 상위클래스 : 뼈대 결정
  • 하위클래스 : 구체적 내용결정

전략 패턴(정책 패턴)

객체의 행위를 바꾸고싶을때 ‘직접’수정하지 않고 전략(캡슐화된 알고리즘)을 컨텍스트 안에서 바꾸어 상호 교체가 가능하게 만드는 패턴

var passport = require('passport')
    , LocalStrategy = require('passport-local').Strategy;

passport.use(new LocalStrategy(
    function(username, password, done) {
        User.findOne({ username: username }, function (err, user) {
          if (err) { return done(err); }
            if (!user) {
                return done(null, false, { message: 'Incorrect username.' });
            }
            if (!user.validPassword(password)) {
                return done(null, false, { message: 'Incorrect password.' });
            }
            return done(null, user);
        });
    }
));

즉 메서드가 인자로 결정되는 객체

옵저버 패턴

주체가 어떤 객체의 상태변화를 관찰하다가 변화가 있을 때 메서드 등을 통해 옵저버 목록에 있는 옵저버들에게 변화를 알려주는 디자인패턴

function createReactiveObject(target, callback) { 
    const proxy = new Proxy(target, {
        set(obj, prop, value){
            if(value !== obj[prop]){
                const prev = obj[prop]
                obj[prop] = value 
                callback(`${prop}가 [${prev}] >> [${value}] 로 변경되었습니다`)
            }
            return true
        }
    })
    return proxy 
} 
const a = {
    "형규" : "솔로"
} 
const b = createReactiveObject(a, console.log)
b.형규 = "솔로"
b.형규 = "커플"
// 형규가 [솔로] >> [커플] 로 변경되었습니다

자바스크립트에서는 프록시 객체를 사용해 구현할 수 있다.

vue3.0프레임워크에서 ref나 reactive정의는 위의 프록시객체로 구현되었다.

프록시 패턴

대상 객체에 접근하기전 그 흐름을 가로채 대상 객체 앞단의 인터페이스 역할을 함

프록시 서버에 활용

프록시 서버: 서버와 클라이언트 사이에서 클라이언트가 자신을 통해 다른 네트워크 서비스에 간접적으로 접속할 수 있게 해주는 것

  • Nginx: node.js 앞단의 프록시서버로 활용되며 다수의 연결을 효과적으로 처리한다.
  • cloudflare: ddos공격 방어 및 Https구축에 사용
  • 프론트 프록시 서버: cors 해결을 위해 사용

이터레이터 패턴

이터레이터를 사용해 컬렉션의 요소들에 접근하는 디자인 패턴

컬렉션의 형태가 다르더라도 이터레이터를 사용해 순회할 수있다.

const mp = new Map() 
mp.set('a', 1)
mp.set('b', 2)
mp.set('cccc', 3) 
const st = new Set() 
st.add(1)
st.add(2)
st.add(3) 
const a = []
for(let i = 0; i < 10; i++)a.push(i)

for(let aa of a) console.log(aa)
for(let a of mp) console.log(a)
for(let a of st) console.log(a) 
/* 
a, b, c 
[ 'a', 1 ]
[ 'b', 2 ]
[ 'c', 3 ]
1
2
3
*/

for of 문 이터레이터 프로토콜을 사용해 순회하는 모습

이터레이터 프로토콜: 이터러블한 객체들은 순회할 때 쓰이는 규칙

이터러블한 객체: 반복 가능한 객체로 배열을 일반화한 객체

노출모듈 패턴

즉시 실행 함수를 통해 접근 제어자를 만드는 패턴

const pukuba = (() => {
    const a = 1
    const b = () => 2
    const public = {
        c : 2, 
        d : () => 3
    }
    return public 
})() 
console.log(pukuba)
console.log(pukuba.a)
// { c: 2, d: [Function: d] }
// undefined

위와같이 캡슐화를 즉시실행함수로 구현하기도 함

mvc 패턴

모델 뷰 컨트롤러로 이루어진 디자인 패턴

  • 모델
    • 데이터, 데이터베이스,상수,변수, 변경시 뷰에 반영
    • 사용자 인터페이스 요소
  • 컨트롤러
    • 하나 이상의 모델과 하나 이상의 뷰를 잇는 디리역할. 메인로직 담당

mvp 패턴

mvc패턴에서 c가 프레젠터로 교체된 패턴

  • 뷰와 프레젠터는 일대일 관계로 더 강한 결합을 가짐
  • 모델의 직접적 뷰 반영을 방지

mvvm 패턴

mvc패턴에서 c가 viewmodel로 교체된 패턴

  • 뷰모델: 뷰를 추상화한 계층
    • 커맨드와 데이터 바인딩을 가짐
      • 뷰와 뷰모델사이 양방향 바인딩을 지원

프로그래밍 패러다임

패러다임


  • 명령형
    • 객체지향형
      • 객체의 집합으로 프로그램의 상호작용을 표현
      • 특징
        • 추상화: 핵심 개념,기능을 간추리는것
        • 캡슐화:속성과 메서드를 묶고 일부를 감춤
        • 상속: 확장가능함
        • 다형성:메서드나 클래스가 다양한 방법으로 동작하는 것 .오버로딩,오버라이딩
      • 설계원칙
        • 단일책임원칙 : 클래스는 각각 하나의 책임을 가져야한다.
        • 개방폐쇄원칙 : 확장에는 열리고 수정에는 닫혀야한다.
        • 리스코프치환원칙 : 자식은 부모를 대체할 수 있다.
        • 인터페이스 분리원칙 : 인터페이스를 분리할수있으면 분리하라
        • 의존역전원칙: 부모나 자식 클래스 모두 추상클래스에 의존해야한다.
    • 절차지향형
      • 연속적인 계산과정
      • 모듈화 어렵, 유지보수성 떨어짐
  • 선언형: 문제를 풀어는것에 집중하는 패러다임 .
    • 함수형

  • 순수함수 : 출력이 입력에만 의존하는 것
  • 고차함수: 함수가 함수를 값처럼 매개변수로 받아 로직을 생성하는 것
    • 언어는 일급객체여야함
반응형
Comments