# CHAPTER 1 디자인 패턴과 프로그래밍 패러다임.

금성·2022년 11월 16일
0

CS 전공지식 노트

목록 보기
1/19

SECTION 1.1 디자인 패턴

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

  • .1 싱글톤 패턴

    하나의 인스턴스만 생성하여 사용하는 디자인 패턴

    인스턴스가 필요할 때, 만들지않고 기존 인스턴스를 활용

    private로 선언 getInstance()메소드를 통해 사용하도록 구현

    객체를 생성할 때마다 메모리 영역을 할당 받아야함 but, new를 통해 객체를 생성한다면 메모리 낭비를 방지 싱글톤으로 구현한 인스턴스는 '전역'이므로, 다른 클래스의 인스턴스들이 데이터를 공유가 가능함.

    -- > 주로 공통된 객체를 여러개 생성해서 사용해야할 때 사용

    개방-폐쇄 원칙에 위배될 우려

    싱글톤 인스턴스가 혼자 너무 많은 일을 하거나, 많은 데이터를 공유 시키면 다른 클래스간 결합도가 높아지는데 이때 개방-폐쇄 원칙에 위배됨

    -- > 유지보수가 힘들고 테스트를 원활하게 진행할 수 없어짐.

    해결책 중 하나 의존성 주입 (DI)

    싱글톤 패턴은 사용하기 쉽고 실용적이지만 모듈간의 결합을 강하게 할 수 있다는 단점이 있음. 이때 의존성 주입을 통해 모듈 간의 결합을 느슨하게 만들어 해결

  • .2 팩토리 패턴

    객체를 만드는 부분을 sub class에 맡기는 패턴

public abstract class Factory {
	abstract Machine createMachine(String name);
}
public class SuperMachineFactory extends Factory {
	@Override
	Machine createMachine(String name) {
		switch(name) {
		case "good" :
			return new GoodFactory();
		case "bad" :
			return new BadFactory();
		}
		return null;
	}
}

name으로 넘어오는 값에 따라 생성되는 Machine이 다르게 설계됨

생성하는 객체를 별도로 두고 넘어오는 값에 따라 다른 결과를 만들어 냄

  • .3 전략 패턴

    어떤 동작을 하는 로직을 정의하고, 캡슐화 관리하는 패턴

    새로운 로직을 추가하거나 변경할 때, 한번에 효율적으로 가능

public interface MemberService {

    void join(Member member);
    Member findMember(Long memberId);
}
public class MemberServiceImpl implements  MemberService{

    private final MemberRepository memberRepository;

    public MemberServiceImpl(MemberRepository memoryMemberRepository) {
        this.memberRepository = memoryMemberRepository;
    }

    @Override
    public void join(Member member) {
        memberRepository.save(member);
    }

    @Override
    public Member findMember(Long memberId) {
        return memberRepository.findById(memberId);
    }
}

구현할 기능 join과 findMember를 인터페이스로 선언 하고 각자 필요한 로직을 클래스로 만들어 implements. / 추상과 구현을 분리

전략적 패턴을 사용하면 로직을 독립적으로 관리하는 것이 편해짐

로직에 들어가는 '구현체'를 클래스로 선언하고 인터페이스와 연결하면됨

  • .4 옵저버 패턴

    상태를 가지고 있는 주체 객체 & 상태의 변경을 알아야 하는 관찰 객체

    서로의 정보의 단위가 클수록 복잡성이 증가 > 가이드라인 = "옵저버 패턴"

  • publisher 인터페이스 ( observer들을 관리하는 메소드 )

    public interface Publisher { 
       public void add(Observer observer); 
       public void delete(Observer observer); 
       public void notifyObserver(); 
    }
  • Machine 구현체 클래스 ( 정보를 제공해주는 퍼블리셔 구현)

    public class Machine implements Publisher {
       private ArrayList<Observer> observers; 
       private String title; 
       private String news; 
    
       public Machine() {
           observers = new ArrayList<>(); 
       }
       
       @Override 
       public void add(Observer observer) {
           observers.add(observer);
       }
       
       @Override 
       public void delete(Observer observer) 	{ 
           int index = observers.indexOf(observer);
           observers.remove(index); 
       }
       
       @Override 
       public void notifyObserver() {
           for(Observer observer : observers) {
              observer.update(title, news); 
           }
       } 
       
       public void setInfo(String title, String news) { 
           this.title = title; 
           this.news = news; 
           notifyObserver(); 
       } 
       
       public String getTitle() { 
       	  return title; 
       } 	
       public String getNews() {
            return news;
      }
    }
  • observer 인터페이스 ( 정보 update )

    public interface Observer { 
       public void update(String title, String news); 
       }
  • EventSubscriber 구현체 클래스 ( )

    • notifyObserver()를 호출하면서 알려줄 때마다 Update가 호출됨
      public class EventSubscriber implements Observer {
        
        private String newsString;
        private Publisher publisher;
        
        public EventSubscriber(Publisher publisher) {
            this.publisher = publisher;
            publisher.add(this);
        }
        
        @Override
        public void update(String title, String news) {
            newsString = title + " " + news;
            display();
        }
        
        public void withdraw() {
            publisher.delete(this);
        }
        
        public void display() {
            System.out.println("이벤트 유저");
            System.out.println(newsString);
        }
      }
  • Java에는 옵저버 패턴을 적용한 것들을 기본적으로 제공 해줌

    Observer 인터페이스 , Observable 클래스

  • 대표적인 사례

    외부에서 발생한 이벤트(사용자 입력같은)에 대한 응답.

  • .5 프록시 패턴과 프록시 서버

    • 프록시 서버

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

    • 프록시 패턴

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

  • .6 이터레이터 패턴

    무언가 많이 모여있는 것을 하나씩 지정해서 순서대로 처리하는 패턴

    • 장점

      하나씩 꺼내서 처리하는 과정을 구현과 분리할 수 있음

    • Iterator 패턴을 사용
      while (it.hasNext()) {
        Book book = (Book) it.next();
        System.out.println(book.getName());
      }
    • for문 사용
      for (int i = 0; i < bookShelf.getLength(); i++) {
         System.out.println(bookShelf.getBook(i).getName());
      }

결과는 Book 객체의 내용을 꺼내서 보여주는것으로 같으나, 1번은 bookShelf의 구현에 의존하지 않음.

  • .7 노출모듈 패턴

  • .8 MVC 패턴

  • .9 MVP 패턴

  • .10 MVVM 패턴


SECTION 1.2 프로그래밍 패러다임

  • 패러다임의 혼합

    하나의 패러다임을 기반으로 통일하여 서비스를 구축하는 것도 좋은 생각이지만 여러 패러다임을 조합하여 상황과 맥락에 따라 패러다임 간의 장점만 취해 개발 하는것이 좋음

  • .1 명령형 프로그래밍 ( HOW )

    알고리즘을 명시하고 목표는 명시하지 않는다.

    • 객체지향 프로그래밍

      객체들의 집합으로 프로그램의 상호작용 표현

      '객체' 라는 기본 단위로 나누고 이들의 상호작용으로 서술

      클래스를 이용해 연관있는 처리부분과(함수) 데이터부분(변수)을 하나의 객체(인스턴스)로 묶어 생성, 사용, 작은 문제를 해결하는 객체를 생성해 큰문제를 해결하는 Bottom-Up 방식

      • 특징

        • 추상화

          • 현실세계 대상을 관찰하여 핵심적인 특징(속성과 행위)을 뽑아내는 과정
          • '객체'는 클래스로 부터 실체화 된것으로 눈에 보이며 실체
          • '클래스'는 추상적이기에 눈에 보이지 않고 개념적으로만 존재
        • 캡슐화

          • 속성과 행위를 관련있는 것끼리 묶는다.
          • 클래스 내부 구현의 '응집도'를 증가
          • 외부 다른 클래스와의 '결합도'를 감소
        • 상속

          • 대상이 되는 클래스의 모든 특징을 물려받는 것
          • 관계가 아래로 내려갈수록 '구체화된다'라고 말한다. => 고유 특징이 증가
          • 관계가 위로 올라올수록 '일반화된다'고 말한다. => 더 많은 객체에 영향을 준다
          • 다형성을 구현하기 위해 사용할 것을 권장
        • 다형성

          하나의 속성이나 행위가 상황에 따라 다른 의미로도 해석될 수 있는 특성

          a. 오버로딩
          - 매개 변수에 따라 여러 종류의 타입을 받아 같은 기능으로 하도록 하기 위한 작업
          - 함수는 변수로 취급하며 모든 변수는 전역 객체로 취급하기 때문에 같은 이름이라면 하나만 취급

          b.오버 라이딩
          - 상위 클래스에 메서드를 하위 클래스에서 재정의 하는 것
          ( 상속 )

    • 절차형 프로그래밍

      수행되어야 할 연속적인 계산 과정을 포함하는 방식

      실행 절차에 중점을 둔 프로그래밍

      • 특징
        • Top-Down 방식
        • 비교적 작은 규모의 작업을 수행하는 함수 생성
        • 인수, 반환 값으로 명령을 전달하고 수행
        • 데이터와 함수를 별개 취급
        • 특정 기능을 수행하려면 해당 메소드를 직접 호출
      • 장점
        • 개인 프로젝트에 적합
        • 객체 지향에 비해 빠름
      • 단점
        • 유지보수가 어렵다
        • 대형 프로젝트에 부적합
        • 분석과 디버깅이 어려움
  • .2 선언형 프로그래밍 ( WHAT )

    • 함수형 프로그래밍

      순수 함수를 보조함수와 조합하고 소프트웨어를 만드는 방식
      로직내 복잡성 해결, 변수사용 억제 -> 상태변경을 피함

      • 특징

        • 일급객체
          • 사용할때 다른 요소와 아무런 차별이 없는 객체
          • 변수나 데이터 구조 안에 담을 수 있음
          • 반환값(return value)로 사용 가능
          • 비교연산이 가능
          • 동적으로 프로퍼티 할당이 가능
        • 불변성
          • 변하지 않는 성질
          • 불변성을 지키기 위해서는 데이터 변경이 필요할 경우 원본을 유지한 채 복사본을 만들어 작업
        • 고차 함수
          • 람다 계산법에서 만들어진 용어
          • 수를 파라미터로 전달할 수 있어야하며 함수의 반환값으로 함수를 사용 가능
        • 순수 함수
          • 동일한 입력에는 항상 같은 값을 반환
          • 함수의 실행은 프로그램의 실행에 영향을 미치지말아야함 (side effect X)
        • 합성 함수
          • 새로운 함수를 만들거나, 계산하기 위해서 둘 이상의 함수를 조합하는 과정을 칭함
  • 차이

    • 절차적 프로그래밍과 객체지향 프로그래밍의 차이

      둘다 명령형 프로그램의 하위 개념이기에 공유하는 것이 많다.

      • 절자척 프로그래밍
        • 프로그램의 순서와 흐름을 먼저 세우고 필요한 자료 구조와 함수를 설계 = 데이터 중심으로 절차적 실행에 초점
      • 객체지향 프로그래밍
        • 절차적 프로그래밍과 반대로 자료구조와 함수를 먼저 설계하고 그 후 실행순서와 흐름을 설계 = 객체간 관계 초점
    • 함수형 프로그래밍과 객체지향 프로그래밍의 차이

      • 객체지향 프로그래밍

        관리하는 모듈함수에 의한 재사용성에 관심을 가지고 있으며 클래스(또는객체,Object)가 일급객체

        • 클래스와 객체들 관계 중심으로 코드 작성
        • 상태, 멤버변수, 메서드 간 긴밀한 관계
        • 멤버 변수의 상태에 따라 결과값이 달라짐
      • 함수형 프로그래밍

        순수함수와 일급객체에 관심을 가지고 있으며 함수(Function)자체가 일급객체

        • 값의 연산 및 결과 도출 중심으로 코드 작성
        • 함수 내부로 넘겨 받은 인자 값을 별도로 저장하지 않음
          -> 간결한 과정으로 처리하고 매핑
profile
내일부터 공부 해야지

0개의 댓글