[CS] 디자인패턴

말랑이·2023년 4월 28일
1

CS

목록 보기
1/3
post-thumbnail

Intro

💖 라이브러리 : 공통으로 사용될 수 있는 특정한 기능들을 모듈화 한 것

  • 규칙 ❌, 프레임워크에 비해 자유로움 (폴더명, 파일명 등)

💖 프레임워크 : 공통으로 사용될 수 있는 특정한 기능들을 모듈화 한 것

  • 규칙 ⭕️, 라이브러리에 비해 엄격함 (폴더명, 파일명 등)

1 싱글톤패턴 singleton pattern

🍋 싱글톤패턴 : 하나의 클래스에 하나의 인스턴스만 가지는 패턴

  • 데이터베이스 연결모듈에 많이 사용
  • A class → a instance ➡️ 로직을 만드는데 사용
  • 하나의 인스턴스를 다른 모듈들이 공유하며 사용
    • 장점 : 비용절감
    • 단점 : 의존성 높음
class DesignPattern1_1 {
    private static class singleInstanceHolder { // 메서드(객체 생성하는)
        // 객체 INSTANCE 생성
        // private로 제한 -> 생성자를 통한 무분별 객체생성 막음
        private static final DesignPattern1_1 INSTANCE = new DesignPattern1_1();
    }
    // getInstance() 메서드 -> 객체반환 (public)
    public static DesignPattern1_1 getInstance() {
        return singleInstanceHolder.INSTANCE;
    }
}

class DesignPattern1_2 {
    public static void main(String[] args) {
        // getInstance()를 통해서 객체(인스턴스) 생성
        DesignPattern1_1 a = DesignPattern1_1.getInstance();
        DesignPattern1_1 b = DesignPattern1_1.getInstance();

        System.out.println(a.hashCode());
        System.out.println(b.hashCode());

        if (a == b) {
            System.out.println(true);
        }
    }
}

📍 Java에서 Singleton ; 프로그램 실행 시, 최초 한번만 메모리 할당
	(메모리고정 -> 낭비최소화)

1️⃣ 싱글톤패턴 단점

📎 TDD(Test-Driven-Development)의 걸림돌이 됨

  • TDD : 테스트주도개발 (선 test → 후 develope)
  • TDD는 단위테스트를 기본으로 함
    • ① 테스트가 서로 독립적 (의존성 ❌)
    • ② 테스트 순서, 방향의 영향 ❌
      ➡️ 싱글톤패턴은 모듈 간 의존성 높아 불가능 ⛔️

2️⃣ 의존성주입 DI

🍋 의존성주입 : 모듈간 결합을 느슨하게 만듬. '느슨한 결합관계' → 싱글톤패턴 단점 해결

  • 의존성(=종속성) : 양방향관계
    • B의 변경 사항에 대해 A 또한 변경
    • A의 변경 사항에 대해 B 또한 변경
  • 의존성 주입 전 : 메인모듈 → 직접 하위모듈에 의존성 부여
  • 의존성 주입 후 : 의존성주입자 → 메인모듈이 간접적으로 의존성 부여
    • ① 의존성 down (느슨한결합)
    • ② 디커플링

3️⃣ 의존성주입 장단점

구분내용
장점모듈 쉽게 교체할 수 있는 구조 → 테스팅 ✅, 마이그레이션 수월함 ✅
장점애플리케이션 의존성 방향 일관
장점애플리케이션 쉽게 추론 가능
단점모듈분리 → 클래스 수 증가로 인한 런타임 패널티

4️⃣ 의존성주입 원칙

📎 의존관계 역전 원칙 📎 단일 책임 원칙

  • 상위모듈은 하위모듈에서 가져오면 ❌
  • 둘 다 추상화에 의존 ✅
  • 추상화는 세부사항에 의존 ❌

5️⃣ Java 의존성주입

// (의존성이 높은 경우, 클래스 간 관계)
class Pencil1 {}

class Store1 {
    private Pencil1 pencil1;

    public Store1() { // 생성자
        this.pencil1 = new Pencil1();
    }
}

// (의존성 주입 -> 느슨한결합형태)
interface Product {} // 다형성 (여러가지 제품을 하나로 표현하는 interface)
class Pencil2 implements Product{}

class Store2 {
    private Product product;

    public Store2(Product product) { // 생성자 (객체를 넣어주는 방식)
        this.product = product;
    }
}

class BeanFactory {
    public void store2() {
        // Bean 생성
        Product pencil2 = new Pencil2();

        // 의존성주입
        Store2 store2 = new Store2(pencil2);
    }
}

2 팩토리패턴 factory pattern

🐱 팩토리패턴
① 객체 생성 부분 떼어냄 → 추상화한 패턴
② 상속 관계 두 클래스 → 상위 클래스 : 뼈대결정 + 하위클래스 : 객체 생성 구체적내용 결정

  • 상위클래스, 하위클래스 분리 ➡️ 느슨한 결합 (의존성 low) ✅
  • 상위클래스 : 인스턴스 생성방식에 대해 알 필요 ❌ ➡️ 더 많은 유연성
  • 객체 생성 로직이 별도로 있음 → 코드 refactoring시 한 곳만 수정 ➡️ 유지보수성 증가

1️⃣ 팩토리패턴 자바코드

// super class -> Lattee, Americano, DefaultCoffee의 부모클래스
abstract class Coffee { // 객체생성부분 추상화
    public abstract int getPrice(); // 메서드

    @Override
    public String toString() { // 메서드
        return "Hi this coffee is " + this.getPrice();
    }
}

class DefaultCoffee extends Coffee {
    private int price; // 멤버변수

    public DefaultCoffee() { // 생성자
        this.price = -1;
    }

    // Coffee 클래스 getPrice() 메서드 -> 생성자로 설정한 값 덮어씌움
    @Override
    public int getPrice() {
        return this.price;
    }
}

class Latte extends Coffee {
    private int price; // 멤버변수

    public Latte(int price) { // 생성자
        this.price = price;
    }

    // Coffee 클래스 getPrice() 메서드 -> 생성자로 설정한 값 덮어씌움
    @Override
    public int getPrice() {
        return this.price;
    }
}

class Americano extends Coffee {
    private int price; // 멤버변수

    public Americano(int price) { // 생성자
        this.price = price;
    }

    // Coffee 클래스 getPrice() 메서드 -> 생성자로 설정한 값 덮어씌움
    @Override
    public int getPrice() {
        return this.price;
    }
}

class CoffeeFactory {
    public static Coffee getCoffee(String type, int price) { // 메서드
        if ("Latte".equalsIgnoreCase(type)) { // 입력값(type) = "Latte"
            return new Latte(price);
        }
        else if ("Americano".equalsIgnoreCase(type)) { // 입력값(type) = "Americano"
            return new Americano(price);
        }
        else {
            return new DefaultCoffee();
        }
    }
}

class DesignPattern1_3 {
    public static void main(String[] args) {
        Coffee latte = CoffeeFactory.getCoffee("Latte", 4000);
        Coffee ame = CoffeeFactory.getCoffee("Americano", 3000);

        System.out.println("Factory latte :: " + latte);
        System.out.println("Factory ame :: " + ame);
    }
}

Factory latte :: Hi this coffee is 4000
Factory ame :: Hi this coffee is 3000

2️⃣ Enum type

📎 상수 및 메서드 집합을 정의할 때 사용되는 type

  • 월, 일, 색상 등 상수값을 담음 (변하지 않는 값, 변수 ⛔️)
  • Enum type 장점
    • 코드 Refactoring → Enum 파일만 수정하면 됨
    • 스레드세이프 (thread safe) → singleton pattern에 용이

3 전략패턴 strategy pattern

🌈 전략패턴 = 정책패턴

  • 객체 행위 수정 → ‘직접’ 수정 ❌
  • 전략 (캡슐화한 알고리즘) → 컨텍스트 안에서 바꿈 ➡️ 상호교체 가능
  • ex. Item 구매 시 → 신한카드(전략1), 삼성카드(전략2) 등 다양한 방법으로 결제하는 것

1️⃣ 전략패턴 자바코드

// 결제 interface
interface PaymentStrategy {
    public void pay(int amount); // pay 메서드
}

// (결제) 전략 1
class KAKAOCardStrategy implements PaymentStrategy {
    private String name;
    private String cardNumber;
    private String cvv;
    private String dateOfExpiry;

    // 생성자
    public KAKAOCardStrategy(String name, String cardNumber, String cvv, String dateOfExpiry) {
        this.name = name;
        this.cardNumber = cardNumber;
        this.cvv = cvv;
        this.dateOfExpiry = dateOfExpiry;
    }

    // PaymentStrategy interface pay 메서드
    @Override
    public void pay(int amount) {
        System.out.println(amount + " paid using KAKAOCard.");
    }
}

// (결제) 전략 2
class LUNACardStrategy implements PaymentStrategy {
    private String email;
    private String password;

    // 생성자
    public LUNACardStrategy (String email, String password) {
        this.email = email;
        this.password = password;
    }

    // PaymentStrategy interface pay 메서드
    @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 price) {
        this.name = name;
        this.price = price;
    }

    // 메서드
    public String getName() {
        return name;
    }

    public int getPrice() {
        return price;
    }
}

// 장바구니 클래스
class ShoppingCart {
    // Item 클래스 리스트 객체
    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 paymentStrategy) {
        int amount = calculateTotal();
        paymentStrategy.pay(amount);
    }
}

class DesignPattern1_4 {
    public static void main(String[] args) {
        // 객체 생성
        ShoppingCart cart = new ShoppingCart();

        Item A = new Item("mallang", 1000);
        Item B = new Item("quokka", 1000);

        cart.addItem(A);
        cart.addItem(B);

        // pay by LUNACard
        cart.pay(new LUNACardStrategy("quokka@gmail.com", "quokka"));

        // pay by KAKAOCard
        cart.pay(new KAKAOCardStrategy("mallang", "mallang123", "123", "04/12"));
    }
}

2000 paid using LUNACard.
2000 paid using KAKAOCard.


4 옵저버패턴 observer pattern

🐰 옵저버패턴
① 주체가 객체의 상태변화 관찰
② 상태변화 감지 → method() 통해 ➡️ 옵저버목록 속, 옵저버에게 변화 notification

  • 주체 : 객체 상태 변화를 보고있는 관찰자
  • 옵저버 : 객체 변화 상태 → 전달되는 메서드 기반 ➡️ '추가 변화 사항'이 생기는 객체
  • 트위터 옵저버 패턴
    • 어떤 사람인 '주체' 팔로우 → 주체가 포스팅 → '알림'이 팔로워한테 감
  • 이벤트 기반 시스템 및 MVC 패턴에 사용됨

1️⃣ 옵저버패턴 구조

  • Model : 주체
  • Controller : 작동
  • View : 옵저버 (→ 변경사항 생기면 '추가변동' 생기는 객체)

① Model(주체)에서 변경사항 발생
② update() 메서드 → View(옵저버)에게 notification
③ 위의 사항 기반으로 Controller 작동

2️⃣ 옵저버패턴 자바코드

interface Subject {
    public void register(Observer obj);
    public void unregister(Observer obj);
    public void notifyObservers();
    public Object getUpdate(Observer obj);
}

interface Observer {
    public void update();
}

// 자바 구현방식 : 부모 interface -> 자식클래스에서 재정의 하여 구현
// 반드시 부모클래스의 메서드를 재정의해야함 (!= 상속 extends)
class Topic implements Subject {
    private List<Observer> observers;
    private String message;

    // 생성자
    public Topic() {
        this.observers = new ArrayList<>();
        this.message = "";
    }

    // 부모클래스 메서드 오버라이드(재정의)
    @Override
    public void register(Observer obj) {
        if (!observers.contains(obj)) observers.add(obj);
    }

    @Override
    public void unregister(Observer obj) {
        observers.remove(obj);
    }

    @Override
    public void notifyObservers() {
        this.observers.forEach(Observer::update);
    }

    @Override
    public Object getUpdate(Observer obj) {
        return this.message;
    }

    public void postMessage(String msg) {
        System.out.println("Message sended to Topic: " + msg);
        this.message = msg;
        notifyObservers();
    }
}

class TopicSubscriber implements Observer {
    private String name;
    private Subject topic;

    // 생성자
    public TopicSubscriber(String name, Subject topic) {
        this.name = name;
        this.topic = topic;
    }

    // 부모클래스 메서드 오버라이드(재정의)
    @Override
    public void update() {
        String msg = (String) topic.getUpdate(this);
        System.out.println(name + ":: got message >> " + msg);
    }
}

class DesignPattern1_5 {
    public static void main(String[] args) {
        // 객체생성
        Topic topic = new Topic();
        Observer a = new TopicSubscriber("a", topic);
        Observer b = new TopicSubscriber("b", topic);
        Observer c = new TopicSubscriber("c", topic);

        topic.register(a);
        topic.register(b);
        topic.register(c);

        topic.postMessage("mallang is crossfit champion!");
    }
}
// topic은 주체이자 객체

Message sended to Topic: mallang is crossfit champion!
a:: got message >> mallang is crossfit champion!
b:: got message >> mallang is crossfit champion!
c:: got message >> mallang is crossfit champion!

3️⃣ 자바 상속과 구현

🐰 상속(extends) : 자식클래스가 부모클래스의 메서드 등을 상속받아 사용

  • 자식클래스에서 추가 및 확장 ✅
  • 재사용성, 중복성의 최소화 장점 ✅
  • 일반클래스, abstract(추상화)클래스 기반 구현방식

🐰 구현(implements) : 부모 interface를 자식클래스에서 재정의하여 구현 (@Override)

  • 상속과 달리 반드시 부모클래스의 메서드를 재정의하여 구현해야함 ⭐️
  • interface 기반 구현방식

5 프록시패턴, 프록시서버 proxy pattern & server

🎈 프록시패턴
① 대상객체(subject) 접근 전, 접근에 대한 흐름을 가로챔
② 대상객체(subject) 앞단의 인터페이스 역할을 하는 디자인패턴

  • 객체 속성, 변환 보완
  • 보안, 데이터검증, 캐싱, 로깅에 활용

1️⃣ 프록시패턴 구조

2️⃣ 프록시서버에서의 캐싱

  • 캐시(임시저장소) 안에 정보를 담아둠
  • 캐시안의 정보 d1, d2 Request에 대해 원격저장소에 Request ❌
  • 캐시(임시저장소) 안의 데이터를 활용
  • 불필요한 외부연결 ❌ ➡️ 트래픽감소효과

🎈 프록시서버 : Server와 Client사이 → Client가 자신을 통해 다른 네트워크 서비스에 간접적으로 접속할 수 있게 해주는 컴퓨터시스템 or 응용프로그램

1️⃣ nginx

🎈 nginx : 비동기 이벤트기반구조와 다수의 연결을 효과적으로 처리가능한 웹서버 (Node.js 서버 앞단 프록시 서버로 활용)

Node.js 버퍼오버플로우 취약점 해결방안

  • nginx를 프록시서버로 앞단에 위치 + Node.js 뒤쪽에 위치
  1. 익명 Client → 직접적 서버 접근 차단 ⛔️
  2. 간접적으로 한단계 더 거침 → 보안강화 ✅

2️⃣ CloudFlare

🎈 CloudFlare : 전 세계적으로 분산된 서버 → 시스템 콘텐츠 전달을 빨리 할 수 있는 CDN 서비스

CDN (콘텐츠 전송 네트워크)

  • 데이터 사용량이 많은 application → 웹페이지 로드속도를 높이는 상호연결서버 네트워크
  • User가 인터넷 접속하는 곳과 가까운 곳 → 콘텐츠 캐싱 or 배포하는 서버네트워크
    ➡️ 사용자가 웹 서버로부터 콘텐츠를 다운로드하는 시간을 줄일 수 있음

1. DDOS 공격방어

📎 DDOS
① 짧은기간 → 네트워크에 많은 Request를 보내 네트워크 마비
② 웹사이트 가용성을 방해 사이버공격
  • CloudFlare가 의심스러운 트래픽, (Client ❌)시스템으로부터 오는 트래픽 → 자동차단하여 공격으로부터 보호
  • 거대 네트워크 용량 + 캐싱전략 → DDOS 막아냄

2. HTTPS 구축

  • 별도의 인증서 ❌ → 손쉽게 구축

3. 트래픽 보안

  • 서비스 배포 이후, 해외에서 의심스러운 트래픽 발생 → CAPTCHA 기반으로 막음 → 클라우드 요금폭탄 방지⛔️

3️⃣ CORS (Cross-Origin Resource Sharing)

🎈 CORS : 서버가 웹 브라우저에서 리소스 다운 시, 다른 오리진을 통해 로드하지 못하게 하는 HTTP Header 기반 메커니즘

📎 오리진 origin
- 프로토콜 + host(IP) + port 조합
- https://mallang.com:8000
  → https:// 프로토콜, mallang.com 호스트, 8000 포트

CORS ERROR

  • FrontEnd port와 BackEnd port 불일치해서 발생
  • 프록시 서버 → FrontEnd 서버에서 요청되는 오리진 → BackEnd 서버에 맞춰 오리진 변경
    • 127.0.0.1 → 루프백(loopback) IP, 본인 PC 서버 IP
    • localhost or 127.0.0.1 + port 번호 → DNS 거치지 않고 바로 본인 PC 서버로 연결됨
📎 DNS (도메인이름시스템)
- mallang 도메인 → 127.0.0.1 머신 IP 주소로 변환

profile
🐱Sunyeon-Jeong, mallang developer🐰

1개의 댓글

comment-user-thumbnail
2023년 5월 12일

사전이 따로 없네요~ 훌륭합니다. ㅋㅋ 목차가 왼쪽에 있으면 더 좋을거 같아요

답글 달기