공통으로 사용될 수 있는 특정한 기능들을 모듈화
- 라이브러리: 폴더명, 파일명 등에 대한 규칙 X, 프레임워크에 비해 자유로움
- ex. 무언가 자를 때 '도구'인 '가위' 사용해서 '내가' 직접 컨트롤
- 프레임워크: 폴더명, 파일명 등에 대한 규칙 O, 라이브러리에 비해 엄격
- ex. 다른 곳으로 이동할 때 '도구'인 비행기를 타고 이동 -> '비행기'가 컨트롤, 나는 앉아 있어야 함
SECTION 1 디자인 패턴
프로그램을 설계할 때 발생했던 문제점
-> 객체 간의 상호 관계 등 이용해 해결할 수 있도록 하나의 규약 형태로 만들어 놓은 것
1. 싱글톤 패턴(singleton pattern)
하나의 클래스에 오직 하나의 인스턴스만 가지는 패턴
(하나의 클래스를 기반으로 여러 개의 개별적인 인스턴스를 만들 수 있음)
- 데이터베이스 연결 모듈에 사용
const URL = 'mongodb://localhost:27017/test'
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
- (+) 인스턴스 생성할 때 드는 비용 ↓
- (-) 의존성(종속성) ↑
- (-) TDD(Test Driven Development)
- 단위 테스트를 주로 하는데 미리 생성된 하나의 인스턴스를 기반으로 구현하는 패턴
-> 각 테스트마다 독립적인 인스턴스 만들기 어려움- 단위 테스트: 테스트 서로 독립적/ 테스트를 어떤 순서로든 실행할 수 있어야 함
- 단위 테스트를 주로 하는데 미리 생성된 하나의 인스턴스를 기반으로 구현하는 패턴
<자바스크립트>
리터럴 {} or `new Object`로 객체 생성 -> 다른 어떤 객체와도 같지 X
class Singleton {
constructor() {
if (!Signleton.instance) {
Singletone.instance = this
}
return Signletone.instance
}
getInstance() {
return this.instance
}
}
const a = new Signleton()
const b = new Signleton()
console.log(a === b) // true
<자바>
class Singleton {
private static class singleInstanceHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return singleInstanceHolder.INSTANCE;
}
}
public class HelloWorld {
public staticvoid main(String[] args) {
Singleton a = Signleton.getInstance();
Singleton b = Signleton.getInstance();
System.out.println(a.hashCode());
System.out.println(b.hashCode());
if (a == b) {
System.out.println(true); // true
}
}
}
의존성 주입(DI; Dependency Injection)

- 의존성 ↑ 해결
- 메인 모듈) 직접 다른 하위 모듈에 대한 의존성 주기 -> 의존성 주입자가 이 부분을 가로챔
=> 메인 모듈) 간접적으로 의존성 주입- 메인 모듈(상위 모듈)은 하위 모듈에 대한 의존성 ↓: 디커플링이 된다
- 원칙
- 상위 모듈은 하위 모듈에서 어떤 것도 가져오지 않아야 함
- 둘다 추상화에 의존, 추상화는 세부 사항에 의존 X
- (+) 모듈을 쉽게 교체할 수 있는 구조가 됨 -> 테스팅 쉽고 마이그레이션하기 수월
- (+) 구현할 때 추상화 레이어를 넣고 이를 기반으로 구현체를 넣어줌
-> 애플리케이션 의존성 방향 일관, 애플리케이션 쉽게 추론, 모듈 간의 관계 명확 - (-) 모듈이 더욱더 분리 -> 클래스 수 ↑ -> 복잡성 ↑, 약간의 런타임 페널티 생기기도 함
2. 팩토리 패턴(factory pattern)
객체를 사용하는 코드에서 객체 생성 부분을 떼어내 추상화한 패턴
- 상속 관계에 있는 두 클래스 -> 상위 클래스: 중요한 뼈대 결정/ 하위 클래스: 객체 생성에 관한 구체적인 내용 결정
- 상위/하위 클래스 분리 => 느슨한 결합
- 상위 클래스: 인스턴스 생성 방식에 대해 알 필요 X -> 유연성 ↑
- 코드 리팩터링해도 한 곳만 수정 -> 유지 보수성 ↑
- ex. 상위 클래스: 바리스타 공장에서 생산/ 하위 클래스: 라떼 레시피, 아메리카노 레시피, 우유 레시피
<자바스크립트>
`new Object()`로 구현, 전달받은 값에 따라 다른 객체 생성, 인스턴스의 타입 등 정함
`static` 정적 메서드 -> 클래스의 인스턴스 X 호출 가능 => 메모리 절약, 개별 인스턴스에 묶이지 않으며 클래스 내의 함수 정의 O
class Latte {
constructor() {
this.name = "latte"
}
}
class Espresso {
constructor() {
this.name = "Espresso"
}
}
clas LatteFactory {
static createCoffe() {
return new Latte()
}
}
class EspressoFactory {
static createCoffe() {
return new Espresso()
}
}
const factoryList = { LatteFactory, EspressoFactory }
class CoffeFactory {
static createCoffe(type) {
const factory = factoryList[type]
return factory.createCoffee()
}
}
const main = () => {
// 라떼 커피 주문
const coffee = CoffeFactory.createCoffee("LatteFactory")
// 커피 이름
console.log(coffee.name) // true
}
main()
상위 클래스: `CoffeeFactory`가 중요한 뼈대 결정/ 하위 클래스: `LatteFactory`가 구체적인 내용 결정
`CoffeeFactory`에서 `LatteFactory`의 인스턴스 생성 X,
`LatteFactory`에서 생성한 인스턴스 -> `CoffeeFactory`에 주입
=> 의존성 주입
<자바>
abstract class Coffee {
public abstract int getPrice();
@Override
public String toString() {
return "Hi this coffee is " + this.getPrice();
}
}
class CoffeeFactory {
public static Coffee getCoffee(String type, int price) {
if ("Latte".equalsIgnoreCase(type)) return new Latte(price);
else return DefaultCoffee();
}
}
class DefaultCoffee extends Coffee {
private int price;
public DefaultCoffee() {
this.price = -1;
}
@Override
public int getPrice() {
return this.price;
}
}
class Latte extends Coffee {
private int price;
public Latte(int price) {
this.price = price;
}
@Override
public int getPrice() {
return this.price
}
}
public class HelloWorld {
public static void main(String[] args) {
Coffee latte = CoffeeFactory.getCoffee("Latte", 4000);
System.out.println("Factory latte :: " + latte);
// Factory latte :: Hi this coffee is 4000
}
}
3. 전략 패턴(strategy pattern) = 정책 패턴(policy pattern)
객체의 행위를 바꾸고 싶은 경우 직접 수정 X
전략이라고 부르는 캡슐화한 알고리즘 -> 컨텍스트 안에서 바꿔주면서 상호 교체가 가능하게 만드는 패턴
ex. 결제 방식의 전략 바꿔서 결제(네이버페이, 카카오페이)
import java.text.*;
import java.util.*;
interface PaymentStrategy {
public void pay(int amount);
}
class KAKAOStrategy implements PaymentStrategy {
private String name;
private String cardNumber;
private String cvv;
private String dateOfExpiry;
public KAKAOStrategy(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 + " payid using Kakao");
}
}
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<>();
}
public void addItem(Item item) {
this.items.add(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("item1", 100);
Item B = new Item("item2", 300);
cart.addItem(A);
cart.addItem(B);
cart.pay(new KAKAOStrategy("asdfasd", "123456789", "123", "05/05"));
// 400 paid using Kakao
}
}
passport 전략 패턴
- 전략 패턴을 활용한 라이브러리
- Node.js에서 인증 모듈을 구현할 때 쓰는 미들웨어 라이브러리
- `LocalStrategy` 전략: 서비스 내의 회원가입된 아이디, 비밀번호 기반으로 인증
- `OAuth` 전략: 페이스북, 네이버 등 다른 서비스를 기반으로 인증
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);
});
}
));
`passport.use(new LocalStrategy( ...`처럼 `passport.use()라는 메서드에 '전략'을 매개변수로 넣어서 로직 수행
4. 옵저버 패턴(observer pattern)

- 주체가 어떤 객체(subject)의 상태 변화를 관찰하다가 상태 변화 O
-> 메서드 ~> 옵저버 목록에 있는 옵저버들에게 변화를 알려주는 디자인 패턴- 주체: 객체의 상태를 변화를 보고 있는 관찰자
- 옵저버들: 객체의 상태 변화에 따라 전달되는 메서드 등을 기반으로 추가 변화 사항이 생기는 객체들
- 주체와 객체를 따로 두지 않고 상태가 변경되는 객체를 기반으로 구축하기도 함
- ex. 트위터: 어떤 사람인 주체 '팔로우' -> 주체가 포스팅 올리게 되면 알림이 '팔로워'에게 감
- 이벤트 기반 시스템, MVC 패턴에 사용
- ex. 모델(주체) 변경 사항 -> `update()` 메서드로 뷰(옵저버)에 알려줌-> 이를 기반으로 컨트롤러 작동
<자바스크립트>
프록시(proxy) 객체 ~> 구현
- 어떠한 대상의 기본적인 동작(속성 접근, 할당, 순회, 열거, 함수 호출 등)의 작업을 가로챌 수 있는 객체
- 2개의 매개변수
- `target`: 프록시할 대상
- `handler`: 프록시 객체의 `target` 동작을 가로채서 정의할 동작들이 정해져 있는 함수
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}rk [${prev}] >> [${value}] 로 변경되었습니다. `)
}
return true
}
})
return proxy
}
const b = createReactiveObject(a, console.log)
b.형규 = "솔로"
b.형규 = "커플"
// 형규가 [솔로] >> [커플] 로 변경되었습니다
<자바>
import java.util.*;
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();
}
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 (lobservers.contains(obj)) observers.add(obj);
}
@Override
public void unregister(Observer obj) {
observers. remove(obj);
}
@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) ;
}
}
public class HelloWorld {
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("amumu is op champion!!");
}
}
/*
Message sended to Topic: amumu is op champion!!
a:: got message >> amumu is op champion!!
b:: got message > amumu is op champion!!
c:: got message >> amumu is op champion!!
*/
`topic` 기반으로 옵저버 패턴 구현/ `topic`: 주체이자 객체
Subject interface 구현: `class Topic implements Subject`
옵저버 선언할 때 해당 이름과 어떠한 토픽의 옵저버가 될 것인지 정함
`Observer a = new TopicSubscriber("a", topic);`
- 상속(`extends`)
- 자식 클래스가 부모 클래스의 메서드 등을 상속받아 사용, 자식 클래스에서 추가/확장 할 수 있는 것
- 재사용성, 중복성의 최소화
- 일반 클래스, `abstract` 클래스 기반으로 구현
- 구현(`implements`)
- 부모 인터페이스 -> 자식 클래스에서 재정의하여 구현하는 것
- 반드시 부모 클래스의 메서드를 재정의하여 구현해야 함
- 인터페이스 기반으로 구현
Vue.js 3.0: `ref` or `reactive`로 정의 -> 해당 값이 변경되었을 때 자동으로 DOM에 있는 값 변경
=> 프록시 객체를 이용한 옵저버 패턴을 이용하여 구현한 것
DOM(Document Object Model): 문서 객체 모델, 웹 브라우저상의 화면을 이루고 있는 요소
5. 프록시 패턴과 프록시 서버
프록시 패턴(proxy pattern)
- 대상 객체(subject)에 접근하기 전 그 접근에 대한 흐름을 가로채 대상 객체 앞단의 인터페이스 역할 하는 디자인 패턴
- 객체의 속성, 변환 등 보완
- 보안, 데이터 검증, 캐싱, 로깅에 사용
- 프록시 객체로 쓰이기도 하지만 프록시 서버로도 활용
프록시 서버(proxy server)
- 서버와 클라이언트 사이, 클라이언트가 자신 ~> 다른 네트워크 서비스에 간접적으로 접속 O 컴퓨터 시스템/응용 프로그램
- nginx: 비동기 이벤트 기반의 구조, 다수의 연결을 효과적으로 처리 가능한 웹 서버
- Node.js의 버퍼 오버플로우 취약점 예방 -> nginx를 프록시 서버로 활용
버퍼: 데이터가 저장되는 메모리 공간/ 버퍼 오버플로우: 메모리 공간을 벗어나는 경우
, 사용되지 않아야 할 영역에 데이터가 덮어씌워져 주소, 값을 바꾸는 공격이 발생하기도 함- => 익명의 사용자의 직접적인 서버로의 접근 차단, 간접적으로 한 단계 더 거침 -> 보안성 강화
- 실제 포트 숨김/ 정적 자원 gzip 압축/ 메인 서버 앞단에서의 로깅
LZ77과 Huffman 코딩 조합인 DEFLATE 알고리즘을 기반으로 한 압축 기술
- Node.js의 버퍼 오버플로우 취약점 예방 -> nginx를 프록시 서버로 활용
- CloudFlare: 전 세계적으로 분산된 서버가 있고 이를 통해 어떠한 시스템의 콘텐츠 전달을 빠르게 할 수 있는 CDN 서비스
CDN(Content Delivery Network): 각 사용자가 인터넷에 접속하는 곳과 가까운 곳에서 콘텐츠를 캐싱/배포하는 서버 네트워크
~> 사용자가 웹 서버로부터 콘텐츠를 다운로드하는 시간 ↓
- DDOS 공격 방어, HTTPS 구축(별도의 인증서 설치 X)
- DDOS: 짧은 기간 동안 네트워크에 많은 요청 -> 네트워크 마비 => 웹 사이트의 가용성 방해하는 사이버 공격 유형
- 의심스로운 트래픽, 특히 사용자 접속 X 시스템 통해 오는 트래픽 자동 차단
- DDOS 공격 방어, HTTPS 구축(별도의 인증서 설치 X)
<CORS와 프론트엔드의 프록시 서버>
- CORS(Cross-Origin Resource Sharing): 서버가 웹 브라우저에서 리소스를 로드할 때 다른 오리진 통해 로드 X
오리진: 프로토콜과 호스트 이름, 포트의 조합- HTTP 헤더 기반 메커니즘
- 프론트엔드 개발 -> 프론트엔드 서버를 만들어서 백엔드 서버와 통신할 때 CORS 에러
- (해결) 프론트엔드에서 프록시서버 만들기도 함
6. 이터레이터 패턴(iterator pattern)
이터레이터 사용 -> 컬렉션(collection)의 요소들에 접근하는 디자인 패턴
순회할 수 있는 여러 가지 자료형의 구조와 상관 X 이터레이터라는 하나의 인터페이스로 순회 O
<자바스크립트>
const mp = new Map()
mp.set('a', 1)
mp.set('b', 2)
mp.set('c', 3)
const st = new Set()
st.add(1)
st.add(2)
st.add(3)
for (let a of mp) console.log(a)
/*
[ 'a', 1 ]
[ 'b', 2 ]
[ 'c', 3 ]
*/
for (let a of st) console.log(a)
/*
1
2
3
*/
다른 자료 구조인 `set`, `map` But, `for a of b`라는 이터레이터 프로토콜 ~> 순회
이터레이터 프로토콜: 이터러블한 객체들을 순회할 때 쓰이는 규칙
이터러블한 객체: 반복 가능한 객체로 배열을 일반화한 객체
7. 노출모듈 패턴(revealing module pattern)
즉시 실행 함수 ~> `private`, `public` 같은 접근 제어자를 만드는 패턴
<자바스크립트>
접근 제어자 X 전역 범위에서 스크립트 실행
-> 노출모듈 패턴 ~> `private`, `public` 접근 제어자 구현하기도 함: CJS(CommonJS) 모듈 방식
const pukuba = (() => {
const a = 1
const b = () => 2
const public = {
c : 2
d : () => 3
}
return public
})()
console.log(pukuba) // { c: 2, d: [Function: d] }
console.log(pukuba.a) // undefined
a와 b: `private` 범위 / c와 d: `public`범위
8. MVC 패턴
- 모델(Model), 뷰(View), 컨트롤러(Controller)로 이뤄진 디자인 패턴
- 애플리케이션의 구성 요소 -> 3가지 역할로 구분 => 개발 프로세스에서 각각의 구성 요소에만 집중해서 개발
- (+) 재사용성, 확장성 용이
- (-) 애플리케이션 복잡 -> 모델과 뷰의 관계 복잡
- 모델: 애플리케이션의 데이터인 데이터베이스, 상수, 변수 등
- ex. 사각형 모양의 박스 안에 글자 -> 사각형 모양의 박스 위치 정보, 글자 내용, 글자 위치, 글자 포맷(utf-8 등)에 관한 정보를 모두 가지고 있어야 함
- 뷰에서 데이터 생성/수정 -> 컨트롤러 ~> 모델 생성/갱신
- 뷰: inputbox, checkbox, textarea 등 사용자 인터페이스 요소 나타냄
- 모델을 기반으로 사용자가 볼 수 있는 화면
- 모델이 가지고 있는 정보는 따로 저장 X, 단순히 사각형 모양 등 화면에 표시하는 정보만 가지고 있어야 함
- 변경 발생 -> 컨트롤러에 전달
- 컨트롤러: 하나 이상의 모델과 하나 이상의 뷰를 잇는 다리 역할/ 이벤트 등 메인 로직 담당
- 모델과 뷰의 생명주기 관리
- 모델 or 뷰의 변경 통지 -> 해석 => 각각의 구성 요소에 해당 내용에 대해 알려줌
리액트(React.js)
- 유저 인터페이스를 구축하기 위한 라이브러리
- 가상 DOM ~> 실제 DOM을 조작하는 것을 추상화 => 성능 ↑
DOM(Document Object Model): 문서 객체 모델/ 웹 브라우저상의 화면을 이루고 있는 요소들 - 불변성(immutable)
- `state`: `setState` 통해서만 수정 가능
- `props`를 기반으로 해서 만들어지는 컴포넌트: `pureComponent`
- 단방향 바인딩 적용, 자유도 ↑
9. MVP 패턴
- MVC 패턴으로부터 파생
- MVC에서 C에 해당하는 컨트롤러 -> 프레젠더(presenter)
- 뷰와 프레젠터: 일대일 관계 => MVC 패턴보다 더 강한 결합을 지닌 디자인 패턴
10. MVVM 패턴

- MVC에서 C에 해당하는 컨트롤러 -> 뷰모델(view model)
- 뷰모델: 뷰를 더 추상화한 계층
- 커맨드와 데이터 바인딩을 가짐(<-> MVC 패턴)
커맨드: 여러 가지 요소에 대한 처리 -> 하나의 액션으로 처리할 수 있게 하는 기법
/ 데이터 바인딩: 화면에 보이는 데이터와 웹 브라우저의 메모리 데이터 일치시키는 기법, 뷰모델 변경 -> 뷰 변경
- 뷰와 뷰모델 사이의 양방향 데이터 바인딩 지원
- (+) UI를 별도의 코드 수정 X 재사용 O, 단위 테스팅하기 쉬움
뷰(Vue.js)
- 반응형(reactivity)
- `watch`와 `computed` 등으로 쉽게 반응형적인 값 구축
- 함수 사용하지 않고 값 대입만으로도 변수 변경 O
- 양방향 바인딩, html 토대로 컴포넌트를 구축 O
- 재사용 가능한 컴포넌트 기반으로 UI 구축 O
SECTION 2 프로그래밍 패러다임(programming paradigm)
프로그래머에게 프로그래밍의 관점을 갖게 해주는 역할을 하는 개발 방법론
- 선언형
- 함수형: 상태 값을 지니지 않는 함수 값들의 연속으로 생각할 수 있게 함
- 명령어
- 객체지향형: 프로그램을 상호 작용하는 개체들의 집합으로 볼 수 있게 함
- 절차지향형
1. 선언형과 함수형 프로그래밍
- 선언형 프로그래밍(declarative programming)
- 무엇을 풀어내는가에 집중하는 패러다임
- '프로그램은 함수로 이뤄진 것이다'라는 명제가 담겨 있음
- 함수형 프로그래밍(functional programming): 선언형 패러다임의 일종
- 순수 함수 -> 블록처럼 쌓아 로직 구현/ 고차 함수 ~> 재사용성 ↑
- 순수 함수: 출력이 입력에만 의존하는 것
- 고차 함수: 함수가 함수를 값처럼 매개변수로 받아 로직을 생성할 수 있는 것
- 일급 객체라는 특징을 가져야 함
- 변수 or 메서드에 함수를 할당 O
- 함수 안에 함수를 매개변수로 담을 수 O
- 함수가 함수를 반환 O
- 일급 객체라는 특징을 가져야 함
- 순수 함수 -> 블록처럼 쌓아 로직 구현/ 고차 함수 ~> 재사용성 ↑
const ret = [1, 2, 3, 4, 5, 11, 12]
.reduce((max, num) => num > max > num : max, 0)
console.log(ret) // 12
=> 자바스크립트: 단순, 유연, 함수가 일급 객체 -> 함수형 프로그래밍 방식 선호
2. 객체지향 프로그래밍(OOP; Object-Oriented Programming)
- 객체들의 집합으로 프로그램의 상호 작용을 표현
- 데이터를 객체로 취급 -> 객체 내부에 선언된 메서드를 활용하는 방식
- 설계에 시간 소요 ↑, 처리 속도가 다른 프로그래밍 패러다임에 비해 상대적으로 ↓
특징
- 추상화(abstraction): 복잡한 시스템으로부터 핵심적인 개념 or 기능 간추려내는 것
- 캡슐화(encapsulation): 객체의 속서오가 메서드 하나로 묶고 일부를 외부에 감추어 은닉하는 것
- 상속성(inheritance): 상위 클래스 특성 -> 하위 클래스가 이어받아서 재사용/추가/확장
- 코드의 재사용 측명, 계측적인 관계 생성, 유지 보수성 측면에서 중요
- 다형성(polymorphism): 하나의 메서드 or 클래스가 다양한 방법으로 동작하는 것
- 오버로딩(overrloading)
- 같은 이름 가진 메서드 여러 개/ 메서드 타입, 매개변수의 유형, 개수 등으로 여러 개 O
- 컴파일 중에 발생하는 정적 다형성
- 오버라이딩(overriding)
- 메서드 오버라이딩(method overriding)
- 상위 클래스로부터 상속받은 메서드 -> 하위 클래스가 재정의
- 런타임 중에 발생하는 동적 다형성
- 오버로딩(overrloading)
// 오버로딩
class Person {
public void eat(String a) {
System.out.println("I eat" + a);
}
public void eat(String a, String b) {
System.out.println("I eat" + a + " and " + b);
}
}
public class CalculateArea {
publc static void main(String[] args){
Person a = new Person();
a.eat("apple"); // I eat apple
a.eat("tomato", "phodo"); I eat tomato and phodo
}
}
// 오버라이딩
class Animal {
public void bark() {
System.out.println("mumu!");
}
}
class Dog extends Aniaml {
@Override
public void bark() {
System.out.println("wal!!!");
}
}
public class Main {
public static void main(String[] args){
Dog d = new Dog();
d.bark(); // wal!!!
}
}
설계 원칙
- 단일 책임 원칙(SRP, Single Responsibility Principle)
- 모든 클래스는 각각 하나의 책임만 가져야 함
- ex. A라는 로직 존재 -> 어떠한 클래스는 A에 관한 클래스, 수정해도 A와 관련된 수정이어야 함
- 개방-폐쇄 원칙(OCP; Open Closed Principle)
- 유지 보수 사항 생긴다면 코드 쉽게 확장할 수 있도록 함/ 수정할 때는 닫혀 있어야 하는 원칙
- 기존의 코드 잘 변경 X 확장 쉽게 할 수 있어야 함
- 리스코프 치환 원칙(LSP; Liskov Substitution Principle)
- 프로그램의 정확성 깨뜨리지 X 하위 타입의 인스턴스로 바꿀 수 있는 것
- 클래스는 상속, 부모-자식 계층 관계 만들어짐
- 부모 객체에 자식 객체를 넣어도 시스템 문제 X
- 인터페이스 분리 원칙(ISP; Interface Segregation Principle)
- 하나의 일반적인 인터페이스 < 구체적인 여러 개의 인터페이스
- 의존 역전 원칙(DIP; Dependency Inversion Principle)
- 자신보다 변하기 쉬운 것에 의존하던 것 -> 추상화된 인터페이스 or 상위 클래스
-> 변하기 쉬운 것의 변화에 영향 X - ex. 타이어를 갈아끼울 수 있는 틀 -> 다양한 타이어 교체 O
- 상위 계층은 하위 계층의 변화에 대한 구현으로부터 독립해야 함
- 자신보다 변하기 쉬운 것에 의존하던 것 -> 추상화된 인터페이스 or 상위 클래스
3. 절차형 프로그래밍
- 로직이 수행되어야 할 연속적인 계산 과정으로 이뤄짐
- ex. 포트란(fortran)을 이용한 대기 과학 관련 연산 작업, 머신 러닝의 배치 작업
- (+) 코드 가독성 좋음, 실행 속도 ↑
- (-) 모듈화하기 어려움, 유지 보수성 ↓
const ret = [1, 2, 3, 4, 5, 11, 12]
let a = 0
for (let i = 0; i < ret.legnth; i++) {
a = Math.max(ret[i], a)
}
console.log(a) // 12
'💻' 카테고리의 다른 글
공통으로 사용될 수 있는 특정한 기능들을 모듈화
- 라이브러리: 폴더명, 파일명 등에 대한 규칙 X, 프레임워크에 비해 자유로움
- ex. 무언가 자를 때 '도구'인 '가위' 사용해서 '내가' 직접 컨트롤
- 프레임워크: 폴더명, 파일명 등에 대한 규칙 O, 라이브러리에 비해 엄격
- ex. 다른 곳으로 이동할 때 '도구'인 비행기를 타고 이동 -> '비행기'가 컨트롤, 나는 앉아 있어야 함
SECTION 1 디자인 패턴
프로그램을 설계할 때 발생했던 문제점
-> 객체 간의 상호 관계 등 이용해 해결할 수 있도록 하나의 규약 형태로 만들어 놓은 것
1. 싱글톤 패턴(singleton pattern)
하나의 클래스에 오직 하나의 인스턴스만 가지는 패턴
(하나의 클래스를 기반으로 여러 개의 개별적인 인스턴스를 만들 수 있음)
- 데이터베이스 연결 모듈에 사용
const URL = 'mongodb://localhost:27017/test'
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
- (+) 인스턴스 생성할 때 드는 비용 ↓
- (-) 의존성(종속성) ↑
- (-) TDD(Test Driven Development)
- 단위 테스트를 주로 하는데 미리 생성된 하나의 인스턴스를 기반으로 구현하는 패턴
-> 각 테스트마다 독립적인 인스턴스 만들기 어려움- 단위 테스트: 테스트 서로 독립적/ 테스트를 어떤 순서로든 실행할 수 있어야 함
- 단위 테스트를 주로 하는데 미리 생성된 하나의 인스턴스를 기반으로 구현하는 패턴
<자바스크립트>
리터럴 {} or new Object
로 객체 생성 -> 다른 어떤 객체와도 같지 X
class Singleton {
constructor() {
if (!Signleton.instance) {
Singletone.instance = this
}
return Signletone.instance
}
getInstance() {
return this.instance
}
}
const a = new Signleton()
const b = new Signleton()
console.log(a === b) // true
<자바>
class Singleton {
private static class singleInstanceHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return singleInstanceHolder.INSTANCE;
}
}
public class HelloWorld {
public staticvoid main(String[] args) {
Singleton a = Signleton.getInstance();
Singleton b = Signleton.getInstance();
System.out.println(a.hashCode());
System.out.println(b.hashCode());
if (a == b) {
System.out.println(true); // true
}
}
}
의존성 주입(DI; Dependency Injection)

- 의존성 ↑ 해결
- 메인 모듈) 직접 다른 하위 모듈에 대한 의존성 주기 -> 의존성 주입자가 이 부분을 가로챔
=> 메인 모듈) 간접적으로 의존성 주입- 메인 모듈(상위 모듈)은 하위 모듈에 대한 의존성 ↓: 디커플링이 된다
- 원칙
- 상위 모듈은 하위 모듈에서 어떤 것도 가져오지 않아야 함
- 둘다 추상화에 의존, 추상화는 세부 사항에 의존 X
- (+) 모듈을 쉽게 교체할 수 있는 구조가 됨 -> 테스팅 쉽고 마이그레이션하기 수월
- (+) 구현할 때 추상화 레이어를 넣고 이를 기반으로 구현체를 넣어줌
-> 애플리케이션 의존성 방향 일관, 애플리케이션 쉽게 추론, 모듈 간의 관계 명확 - (-) 모듈이 더욱더 분리 -> 클래스 수 ↑ -> 복잡성 ↑, 약간의 런타임 페널티 생기기도 함
2. 팩토리 패턴(factory pattern)
객체를 사용하는 코드에서 객체 생성 부분을 떼어내 추상화한 패턴
- 상속 관계에 있는 두 클래스 -> 상위 클래스: 중요한 뼈대 결정/ 하위 클래스: 객체 생성에 관한 구체적인 내용 결정
- 상위/하위 클래스 분리 => 느슨한 결합
- 상위 클래스: 인스턴스 생성 방식에 대해 알 필요 X -> 유연성 ↑
- 코드 리팩터링해도 한 곳만 수정 -> 유지 보수성 ↑
- ex. 상위 클래스: 바리스타 공장에서 생산/ 하위 클래스: 라떼 레시피, 아메리카노 레시피, 우유 레시피
<자바스크립트>
new Object()
로 구현, 전달받은 값에 따라 다른 객체 생성, 인스턴스의 타입 등 정함
static
정적 메서드 -> 클래스의 인스턴스 X 호출 가능 => 메모리 절약, 개별 인스턴스에 묶이지 않으며 클래스 내의 함수 정의 O
class Latte {
constructor() {
this.name = "latte"
}
}
class Espresso {
constructor() {
this.name = "Espresso"
}
}
clas LatteFactory {
static createCoffe() {
return new Latte()
}
}
class EspressoFactory {
static createCoffe() {
return new Espresso()
}
}
const factoryList = { LatteFactory, EspressoFactory }
class CoffeFactory {
static createCoffe(type) {
const factory = factoryList[type]
return factory.createCoffee()
}
}
const main = () => {
// 라떼 커피 주문
const coffee = CoffeFactory.createCoffee("LatteFactory")
// 커피 이름
console.log(coffee.name) // true
}
main()
상위 클래스:CoffeeFactory
가 중요한 뼈대 결정/ 하위 클래스:LatteFactory
가 구체적인 내용 결정CoffeeFactory
에서LatteFactory
의 인스턴스 생성 X,LatteFactory
에서 생성한 인스턴스 ->CoffeeFactory
에 주입
=> 의존성 주입
<자바>
abstract class Coffee {
public abstract int getPrice();
@Override
public String toString() {
return "Hi this coffee is " + this.getPrice();
}
}
class CoffeeFactory {
public static Coffee getCoffee(String type, int price) {
if ("Latte".equalsIgnoreCase(type)) return new Latte(price);
else return DefaultCoffee();
}
}
class DefaultCoffee extends Coffee {
private int price;
public DefaultCoffee() {
this.price = -1;
}
@Override
public int getPrice() {
return this.price;
}
}
class Latte extends Coffee {
private int price;
public Latte(int price) {
this.price = price;
}
@Override
public int getPrice() {
return this.price
}
}
public class HelloWorld {
public static void main(String[] args) {
Coffee latte = CoffeeFactory.getCoffee("Latte", 4000);
System.out.println("Factory latte :: " + latte);
// Factory latte :: Hi this coffee is 4000
}
}
3. 전략 패턴(strategy pattern) = 정책 패턴(policy pattern)
객체의 행위를 바꾸고 싶은 경우 직접 수정 X
전략이라고 부르는 캡슐화한 알고리즘 -> 컨텍스트 안에서 바꿔주면서 상호 교체가 가능하게 만드는 패턴
ex. 결제 방식의 전략 바꿔서 결제(네이버페이, 카카오페이)
import java.text.*;
import java.util.*;
interface PaymentStrategy {
public void pay(int amount);
}
class KAKAOStrategy implements PaymentStrategy {
private String name;
private String cardNumber;
private String cvv;
private String dateOfExpiry;
public KAKAOStrategy(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 + " payid using Kakao");
}
}
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<>();
}
public void addItem(Item item) {
this.items.add(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("item1", 100);
Item B = new Item("item2", 300);
cart.addItem(A);
cart.addItem(B);
cart.pay(new KAKAOStrategy("asdfasd", "123456789", "123", "05/05"));
// 400 paid using Kakao
}
}
passport 전략 패턴
- 전략 패턴을 활용한 라이브러리
- Node.js에서 인증 모듈을 구현할 때 쓰는 미들웨어 라이브러리
LocalStrategy
전략: 서비스 내의 회원가입된 아이디, 비밀번호 기반으로 인증OAuth
전략: 페이스북, 네이버 등 다른 서비스를 기반으로 인증
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);
});
}
));
passport.use(new LocalStrategy( ...
처럼 `passport.use()라는 메서드에 '전략'을 매개변수로 넣어서 로직 수행
4. 옵저버 패턴(observer pattern)

- 주체가 어떤 객체(subject)의 상태 변화를 관찰하다가 상태 변화 O
-> 메서드 ~> 옵저버 목록에 있는 옵저버들에게 변화를 알려주는 디자인 패턴- 주체: 객체의 상태를 변화를 보고 있는 관찰자
- 옵저버들: 객체의 상태 변화에 따라 전달되는 메서드 등을 기반으로 추가 변화 사항이 생기는 객체들
- 주체와 객체를 따로 두지 않고 상태가 변경되는 객체를 기반으로 구축하기도 함
- ex. 트위터: 어떤 사람인 주체 '팔로우' -> 주체가 포스팅 올리게 되면 알림이 '팔로워'에게 감
- 이벤트 기반 시스템, MVC 패턴에 사용
- ex. 모델(주체) 변경 사항 ->
update()
메서드로 뷰(옵저버)에 알려줌-> 이를 기반으로 컨트롤러 작동
- ex. 모델(주체) 변경 사항 ->
<자바스크립트>
프록시(proxy) 객체 ~> 구현
- 어떠한 대상의 기본적인 동작(속성 접근, 할당, 순회, 열거, 함수 호출 등)의 작업을 가로챌 수 있는 객체
- 2개의 매개변수
target
: 프록시할 대상handler
: 프록시 객체의target
동작을 가로채서 정의할 동작들이 정해져 있는 함수
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}rk [${prev}] >> [${value}] 로 변경되었습니다. `)
}
return true
}
})
return proxy
}
const b = createReactiveObject(a, console.log)
b.형규 = "솔로"
b.형규 = "커플"
// 형규가 [솔로] >> [커플] 로 변경되었습니다
<자바>
import java.util.*;
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();
}
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 (lobservers.contains(obj)) observers.add(obj);
}
@Override
public void unregister(Observer obj) {
observers. remove(obj);
}
@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) ;
}
}
public class HelloWorld {
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("amumu is op champion!!");
}
}
/*
Message sended to Topic: amumu is op champion!!
a:: got message >> amumu is op champion!!
b:: got message > amumu is op champion!!
c:: got message >> amumu is op champion!!
*/
topic
기반으로 옵저버 패턴 구현/topic
: 주체이자 객체
Subject interface 구현:class Topic implements Subject
옵저버 선언할 때 해당 이름과 어떠한 토픽의 옵저버가 될 것인지 정함Observer a = new TopicSubscriber("a", topic);
- 상속(
extends
)- 자식 클래스가 부모 클래스의 메서드 등을 상속받아 사용, 자식 클래스에서 추가/확장 할 수 있는 것
- 재사용성, 중복성의 최소화
- 일반 클래스,
abstract
클래스 기반으로 구현
- 구현(
implements
)- 부모 인터페이스 -> 자식 클래스에서 재정의하여 구현하는 것
- 반드시 부모 클래스의 메서드를 재정의하여 구현해야 함
- 인터페이스 기반으로 구현
Vue.js 3.0: ref
or reactive
로 정의 -> 해당 값이 변경되었을 때 자동으로 DOM에 있는 값 변경
=> 프록시 객체를 이용한 옵저버 패턴을 이용하여 구현한 것
DOM(Document Object Model): 문서 객체 모델, 웹 브라우저상의 화면을 이루고 있는 요소
5. 프록시 패턴과 프록시 서버
프록시 패턴(proxy pattern)
- 대상 객체(subject)에 접근하기 전 그 접근에 대한 흐름을 가로채 대상 객체 앞단의 인터페이스 역할 하는 디자인 패턴
- 객체의 속성, 변환 등 보완
- 보안, 데이터 검증, 캐싱, 로깅에 사용
- 프록시 객체로 쓰이기도 하지만 프록시 서버로도 활용
프록시 서버(proxy server)
- 서버와 클라이언트 사이, 클라이언트가 자신 ~> 다른 네트워크 서비스에 간접적으로 접속 O 컴퓨터 시스템/응용 프로그램
- nginx: 비동기 이벤트 기반의 구조, 다수의 연결을 효과적으로 처리 가능한 웹 서버
- Node.js의 버퍼 오버플로우 취약점 예방 -> nginx를 프록시 서버로 활용
버퍼: 데이터가 저장되는 메모리 공간/ 버퍼 오버플로우: 메모리 공간을 벗어나는 경우
, 사용되지 않아야 할 영역에 데이터가 덮어씌워져 주소, 값을 바꾸는 공격이 발생하기도 함- => 익명의 사용자의 직접적인 서버로의 접근 차단, 간접적으로 한 단계 더 거침 -> 보안성 강화
- 실제 포트 숨김/ 정적 자원 gzip 압축/ 메인 서버 앞단에서의 로깅
LZ77과 Huffman 코딩 조합인 DEFLATE 알고리즘을 기반으로 한 압축 기술
- Node.js의 버퍼 오버플로우 취약점 예방 -> nginx를 프록시 서버로 활용
- CloudFlare: 전 세계적으로 분산된 서버가 있고 이를 통해 어떠한 시스템의 콘텐츠 전달을 빠르게 할 수 있는 CDN 서비스
CDN(Content Delivery Network): 각 사용자가 인터넷에 접속하는 곳과 가까운 곳에서 콘텐츠를 캐싱/배포하는 서버 네트워크
~> 사용자가 웹 서버로부터 콘텐츠를 다운로드하는 시간 ↓
- DDOS 공격 방어, HTTPS 구축(별도의 인증서 설치 X)
- DDOS: 짧은 기간 동안 네트워크에 많은 요청 -> 네트워크 마비 => 웹 사이트의 가용성 방해하는 사이버 공격 유형
- 의심스로운 트래픽, 특히 사용자 접속 X 시스템 통해 오는 트래픽 자동 차단
- DDOS 공격 방어, HTTPS 구축(별도의 인증서 설치 X)
<CORS와 프론트엔드의 프록시 서버>
- CORS(Cross-Origin Resource Sharing): 서버가 웹 브라우저에서 리소스를 로드할 때 다른 오리진 통해 로드 X
오리진: 프로토콜과 호스트 이름, 포트의 조합- HTTP 헤더 기반 메커니즘
- 프론트엔드 개발 -> 프론트엔드 서버를 만들어서 백엔드 서버와 통신할 때 CORS 에러
- (해결) 프론트엔드에서 프록시서버 만들기도 함
6. 이터레이터 패턴(iterator pattern)
이터레이터 사용 -> 컬렉션(collection)의 요소들에 접근하는 디자인 패턴
순회할 수 있는 여러 가지 자료형의 구조와 상관 X 이터레이터라는 하나의 인터페이스로 순회 O
<자바스크립트>
const mp = new Map()
mp.set('a', 1)
mp.set('b', 2)
mp.set('c', 3)
const st = new Set()
st.add(1)
st.add(2)
st.add(3)
for (let a of mp) console.log(a)
/*
[ 'a', 1 ]
[ 'b', 2 ]
[ 'c', 3 ]
*/
for (let a of st) console.log(a)
/*
1
2
3
*/
다른 자료 구조인set
,map
But,for a of b
라는 이터레이터 프로토콜 ~> 순회
이터레이터 프로토콜: 이터러블한 객체들을 순회할 때 쓰이는 규칙
이터러블한 객체: 반복 가능한 객체로 배열을 일반화한 객체
7. 노출모듈 패턴(revealing module pattern)
즉시 실행 함수 ~> private
, public
같은 접근 제어자를 만드는 패턴
<자바스크립트>
접근 제어자 X 전역 범위에서 스크립트 실행
-> 노출모듈 패턴 ~> private
, public
접근 제어자 구현하기도 함: CJS(CommonJS) 모듈 방식
const pukuba = (() => {
const a = 1
const b = () => 2
const public = {
c : 2
d : () => 3
}
return public
})()
console.log(pukuba) // { c: 2, d: [Function: d] }
console.log(pukuba.a) // undefined
a와 b:private
범위 / c와 d:public
범위
8. MVC 패턴
- 모델(Model), 뷰(View), 컨트롤러(Controller)로 이뤄진 디자인 패턴
- 애플리케이션의 구성 요소 -> 3가지 역할로 구분 => 개발 프로세스에서 각각의 구성 요소에만 집중해서 개발
- (+) 재사용성, 확장성 용이
- (-) 애플리케이션 복잡 -> 모델과 뷰의 관계 복잡
- 모델: 애플리케이션의 데이터인 데이터베이스, 상수, 변수 등
- ex. 사각형 모양의 박스 안에 글자 -> 사각형 모양의 박스 위치 정보, 글자 내용, 글자 위치, 글자 포맷(utf-8 등)에 관한 정보를 모두 가지고 있어야 함
- 뷰에서 데이터 생성/수정 -> 컨트롤러 ~> 모델 생성/갱신
- 뷰: inputbox, checkbox, textarea 등 사용자 인터페이스 요소 나타냄
- 모델을 기반으로 사용자가 볼 수 있는 화면
- 모델이 가지고 있는 정보는 따로 저장 X, 단순히 사각형 모양 등 화면에 표시하는 정보만 가지고 있어야 함
- 변경 발생 -> 컨트롤러에 전달
- 컨트롤러: 하나 이상의 모델과 하나 이상의 뷰를 잇는 다리 역할/ 이벤트 등 메인 로직 담당
- 모델과 뷰의 생명주기 관리
- 모델 or 뷰의 변경 통지 -> 해석 => 각각의 구성 요소에 해당 내용에 대해 알려줌
리액트(React.js)
- 유저 인터페이스를 구축하기 위한 라이브러리
- 가상 DOM ~> 실제 DOM을 조작하는 것을 추상화 => 성능 ↑
DOM(Document Object Model): 문서 객체 모델/ 웹 브라우저상의 화면을 이루고 있는 요소들 - 불변성(immutable)
state
:setState
통해서만 수정 가능props
를 기반으로 해서 만들어지는 컴포넌트:pureComponent
- 단방향 바인딩 적용, 자유도 ↑
9. MVP 패턴
- MVC 패턴으로부터 파생
- MVC에서 C에 해당하는 컨트롤러 -> 프레젠더(presenter)
- 뷰와 프레젠터: 일대일 관계 => MVC 패턴보다 더 강한 결합을 지닌 디자인 패턴
10. MVVM 패턴

- MVC에서 C에 해당하는 컨트롤러 -> 뷰모델(view model)
- 뷰모델: 뷰를 더 추상화한 계층
- 커맨드와 데이터 바인딩을 가짐(<-> MVC 패턴)
커맨드: 여러 가지 요소에 대한 처리 -> 하나의 액션으로 처리할 수 있게 하는 기법
/ 데이터 바인딩: 화면에 보이는 데이터와 웹 브라우저의 메모리 데이터 일치시키는 기법, 뷰모델 변경 -> 뷰 변경
- 뷰와 뷰모델 사이의 양방향 데이터 바인딩 지원
- (+) UI를 별도의 코드 수정 X 재사용 O, 단위 테스팅하기 쉬움
뷰(Vue.js)
- 반응형(reactivity)
watch
와computed
등으로 쉽게 반응형적인 값 구축
- 함수 사용하지 않고 값 대입만으로도 변수 변경 O
- 양방향 바인딩, html 토대로 컴포넌트를 구축 O
- 재사용 가능한 컴포넌트 기반으로 UI 구축 O
SECTION 2 프로그래밍 패러다임(programming paradigm)
프로그래머에게 프로그래밍의 관점을 갖게 해주는 역할을 하는 개발 방법론
- 선언형
- 함수형: 상태 값을 지니지 않는 함수 값들의 연속으로 생각할 수 있게 함
- 명령어
- 객체지향형: 프로그램을 상호 작용하는 개체들의 집합으로 볼 수 있게 함
- 절차지향형
1. 선언형과 함수형 프로그래밍
- 선언형 프로그래밍(declarative programming)
- 무엇을 풀어내는가에 집중하는 패러다임
- '프로그램은 함수로 이뤄진 것이다'라는 명제가 담겨 있음
- 함수형 프로그래밍(functional programming): 선언형 패러다임의 일종
- 순수 함수 -> 블록처럼 쌓아 로직 구현/ 고차 함수 ~> 재사용성 ↑
- 순수 함수: 출력이 입력에만 의존하는 것
- 고차 함수: 함수가 함수를 값처럼 매개변수로 받아 로직을 생성할 수 있는 것
- 일급 객체라는 특징을 가져야 함
- 변수 or 메서드에 함수를 할당 O
- 함수 안에 함수를 매개변수로 담을 수 O
- 함수가 함수를 반환 O
- 일급 객체라는 특징을 가져야 함
- 순수 함수 -> 블록처럼 쌓아 로직 구현/ 고차 함수 ~> 재사용성 ↑
const ret = [1, 2, 3, 4, 5, 11, 12]
.reduce((max, num) => num > max > num : max, 0)
console.log(ret) // 12
=> 자바스크립트: 단순, 유연, 함수가 일급 객체 -> 함수형 프로그래밍 방식 선호
2. 객체지향 프로그래밍(OOP; Object-Oriented Programming)
- 객체들의 집합으로 프로그램의 상호 작용을 표현
- 데이터를 객체로 취급 -> 객체 내부에 선언된 메서드를 활용하는 방식
- 설계에 시간 소요 ↑, 처리 속도가 다른 프로그래밍 패러다임에 비해 상대적으로 ↓
특징
- 추상화(abstraction): 복잡한 시스템으로부터 핵심적인 개념 or 기능 간추려내는 것
- 캡슐화(encapsulation): 객체의 속서오가 메서드 하나로 묶고 일부를 외부에 감추어 은닉하는 것
- 상속성(inheritance): 상위 클래스 특성 -> 하위 클래스가 이어받아서 재사용/추가/확장
- 코드의 재사용 측명, 계측적인 관계 생성, 유지 보수성 측면에서 중요
- 다형성(polymorphism): 하나의 메서드 or 클래스가 다양한 방법으로 동작하는 것
- 오버로딩(overrloading)
- 같은 이름 가진 메서드 여러 개/ 메서드 타입, 매개변수의 유형, 개수 등으로 여러 개 O
- 컴파일 중에 발생하는 정적 다형성
- 오버라이딩(overriding)
- 메서드 오버라이딩(method overriding)
- 상위 클래스로부터 상속받은 메서드 -> 하위 클래스가 재정의
- 런타임 중에 발생하는 동적 다형성
- 오버로딩(overrloading)
// 오버로딩
class Person {
public void eat(String a) {
System.out.println("I eat" + a);
}
public void eat(String a, String b) {
System.out.println("I eat" + a + " and " + b);
}
}
public class CalculateArea {
publc static void main(String[] args){
Person a = new Person();
a.eat("apple"); // I eat apple
a.eat("tomato", "phodo"); I eat tomato and phodo
}
}
// 오버라이딩
class Animal {
public void bark() {
System.out.println("mumu!");
}
}
class Dog extends Aniaml {
@Override
public void bark() {
System.out.println("wal!!!");
}
}
public class Main {
public static void main(String[] args){
Dog d = new Dog();
d.bark(); // wal!!!
}
}
설계 원칙
- 단일 책임 원칙(SRP, Single Responsibility Principle)
- 모든 클래스는 각각 하나의 책임만 가져야 함
- ex. A라는 로직 존재 -> 어떠한 클래스는 A에 관한 클래스, 수정해도 A와 관련된 수정이어야 함
- 개방-폐쇄 원칙(OCP; Open Closed Principle)
- 유지 보수 사항 생긴다면 코드 쉽게 확장할 수 있도록 함/ 수정할 때는 닫혀 있어야 하는 원칙
- 기존의 코드 잘 변경 X 확장 쉽게 할 수 있어야 함
- 리스코프 치환 원칙(LSP; Liskov Substitution Principle)
- 프로그램의 정확성 깨뜨리지 X 하위 타입의 인스턴스로 바꿀 수 있는 것
- 클래스는 상속, 부모-자식 계층 관계 만들어짐
- 부모 객체에 자식 객체를 넣어도 시스템 문제 X
- 인터페이스 분리 원칙(ISP; Interface Segregation Principle)
- 하나의 일반적인 인터페이스 < 구체적인 여러 개의 인터페이스
- 의존 역전 원칙(DIP; Dependency Inversion Principle)
- 자신보다 변하기 쉬운 것에 의존하던 것 -> 추상화된 인터페이스 or 상위 클래스
-> 변하기 쉬운 것의 변화에 영향 X - ex. 타이어를 갈아끼울 수 있는 틀 -> 다양한 타이어 교체 O
- 상위 계층은 하위 계층의 변화에 대한 구현으로부터 독립해야 함
- 자신보다 변하기 쉬운 것에 의존하던 것 -> 추상화된 인터페이스 or 상위 클래스
3. 절차형 프로그래밍
- 로직이 수행되어야 할 연속적인 계산 과정으로 이뤄짐
- ex. 포트란(fortran)을 이용한 대기 과학 관련 연산 작업, 머신 러닝의 배치 작업
- (+) 코드 가독성 좋음, 실행 속도 ↑
- (-) 모듈화하기 어려움, 유지 보수성 ↓
const ret = [1, 2, 3, 4, 5, 11, 12]
let a = 0
for (let i = 0; i < ret.legnth; i++) {
a = Math.max(ret[i], a)
}
console.log(a) // 12