- 모든 참가자(Peer)는 동등한 위치에 있고 모든 참가자가 서버와 클라이언트 둘 다 역할을 수행할 수 있는 패턴을 의미합니다. 이 패턴은 분산형 네트워크에서 주로 사용되며 각 참가자가 자신의 자원을 공유하고 다른 참가자의 자원을 사용할 수 있습니다.
- 이로 인해 중앙 서버에 의존하지 않고 데이터를 공유하고 전송할 수 있으며 이는 대규모 데이터를 효율적으로 전송하거나 분산된 시스템에서 작동하는데 이상적인 패턴입니다.
💡 피어 투 피어 패턴(Peer-to-Peer, P2P) 처리과정
- 각각의 Peer는 클라이언트와 서버의 역할을 둘 다 수행합니다. 그렇기에 Peer 간의 데이터를 요청하고 응답을 할 수 있습니다.
- 미디어 데이터를 전송하는 주체가 'Publisher'가 되고 미디어 데이터를 수신하는 주체가 'Subscriber'가 됩니다.
1. 피어 투 피어 패턴의 사용 사례 : WebRTC(Web Real-Time Communication)
💡 피어 투 피어 패턴의 사용 사례 : WebRTC(Web Real-Time Communication)
1. 시스널링(Singnaling)
- 웹 서버를 통해서 상대방의 IP 주소, 포트정보, 통신에 필요한 '메타데이터를 교환'하는 시그널링 과정을 거칩니다. - 해당 과정에서는 WebRTC 프로토콜은 포함되어 있지 않습니다.
2. SDP(Session Description Protocol) 교환
- 시그널링 과정을 통해 Peer A와 Peer B를 서로 찾으면 SDP를 이용하여 미디어 통신을 위한 '세션을 협상'합니다. - SDP는 미디어 포맷, 전송 프로토콜, IP 주소, 포트 번호 등을 포함합니다.
3. ICE(Interactive Connectivity Establishment) 프레임워크를 통한 NAT/Firewall 우회 - 실제 인터넷 환경에서는 NAT(Network Address Translation)이나 Firewall 때문에 직접 통신이 어려울 수 있습니다. - 이를 해결하기 위해 ICE 프레임워크를 사용하여 STUN(Server Traversal Utilities for NAT) 서버나 TURN(Traversal Using Relays around NAT) 서버를 이용하여 NAT/Firewall를 우회하게 됩니다.
4. 미디어 통신
- 이렇게 연결이 완료되면, Peer A와 Peer B는 서로에게 Audio, Video, Data를 직접 전송할 수 있게 됩니다. - 이 과정에서는 RTP(Real-time Transport Protocol)를 사용하여 실시간으로 미디어 데이터를 전송합니다.
[ 더 알아보기 ] 💡 WebRTC(Web Real-Time Communication)
- 웹 브라우저 간에 실시간 통신을 가능하게 하는 오픈 소스 프로젝트입니다. - 기술은 피어 투 피어 연결을 통해 데이터를 직접 교환하므로 중간에 서버를 거치지 않고 빠르게 데이터를 전송할 수 있습니다. 이로 인해 지연 시간이 크게 감소하며, 서버 비용도 절약할 수 있습니다. - 또한, WebRTC는 음성 및 비디오 통화, 텍스트 메시지, 파일 공유 등 다양한 형태의 실시간 통신을 지원합니다. 이 기술의 보안성도 뛰어나, 모든 통신은 기본적으로 암호화됩니다.
8) 이벤트-버스 패턴(Event-Bus Pattern)
💡 이벤트-버스 패턴(Event-Bus Pattern)
- 서로 다른 컴포넌트들 사이에 메시지를 전달하는 매체로 ‘이벤트 버스’를 사용하는 패턴을 의미합니다.
- 이벤트 버스는 중개인 역할을 하며 서로 상호작용을 하는 컴포넌트들 사이에서 직접적인 의존성을 제거하고 유연하고 재 사용 가능한 코드를 작성할 수 있게 돕습니다. - 이벤트-버스 패턴을 사용하면 한 컴포넌트에서 발생한 이벤트를 다른 컴포넌트에서 구독하고 반응할 수 있습니다. 이는 컴포넌트 간의 강력한 결합을 피하고 코드의 유연성을 높이는데 도움이 됩니다. - 하지만 이벤트-버스 패턴은 사용에 주의가 필요합니다. 이 패턴을 과도하게 사용하면, 어떤 이벤트가 어디서 발생했는지, 어떤 컴포넌트가 이벤트를 받고 있는지 추적하기 힘들어지고, 코드의 복잡성이 증가할 수 있습니다. 따라서 이벤트-버스 패턴은 적절히 사용해야 합니다.
구성요소
설명
이벤트 소스(Event Source)
이벤트를 발생시키는 엔티티로, 이벤트의 상태 변경이나 특정 행동을 통해 이벤트를 생성합니다.
이벤트 리스너(Event Listener)
특정 이벤트를 구독하고, 이벤트가 발생하면 반응하여 특정 작업을 수행하는 엔티티입니다.
채널(Channel)
이벤트 소스와 이벤트 리스너 사이에서 이벤트를 전달하는 통신 경로입니다.
이벤트 버스(Event Bus)
이벤트를 생성하고, 전달하며, 처리하는 중계 역할을 하는 시스템입니다.
💡 이벤트-버스 패턴(Event-Bus Pattern) 처리과정
1. 게시자(Publisher)
- 이벤트 소스는 특정 조건이 충족되면 이벤트를 생성합니다. 이 이벤트는 일반적으로 상태 변경이나 특정 행동에 의해 발생합니다.
2. 게시자(Publisher) → (Event) → 이벤트 버스(Event Channel)
- 이벤트를 전달 받은 경우 이벤트 버스로 전달이 됩니다. 이 이벤트 버스에서는 특정 이벤트 채널로 라우팅을 수행합니다.
3. 구독자(Subscriber) = 이벤트 리스너(Event Listener)
- 특정 채널만 구독하고 있던 구독자만 반응하여 이벤트가 전달되어, 해당 이벤트를 기반으로 처리를 수행합니다.
4. 이벤트 리스너가 이벤트를 처리한 후, 해당 이벤트는 소멸됩니다.
1. 이벤트-버스 패턴 사용 사례 : FCM Push Notification
💡 이벤트-버스 패턴 사용 사례 : FCM Push Notification
- 해당 패턴을 사용하는 사례는 A라는 모바일 기기에 B라는 모바일 기기로 FCM 푸시 메시지 전송하는 과정에서 나타납니다.
- FCM 메시지를 전송할 때는 상대방의 FCM ID를 기반으로 다른 디바이스로 전송을 합니다. 이 전송 과정에서 채널이 생성이 되고, 전송받는 디바이스에서는 이벤트 리스너를 통해 이벤트가 들어오기를 기다리고 있습니다. 그리고 이벤트가 들어오게 되면 상대방에게 푸시 메시지가 전송이 됩니다.
💡 전송 처리 과정 - A Mobile이 Publisher가 되어서 푸시 알림을 전송하는 주체가 됩니다.
1. A Mobile은 앱을 실행하여 FCM 메시지를 전송하는 버튼을 누릅니다 : Publisher
2. 서버의 특정 엔드포인트로 호출이 되어서 해당 메시지가 서버에서 처리가 됩니다.
3. 리스너에서는 Publisher로 부터 이벤트(메시지)를 전달 받으면 FCM 메시지를 출력 할 수 있도록 이벤트를 수신하고 있습니다.
💡 수신 처리 과정(대기)
- B Mobile은 FCM 메시지를 전송받기 위한 Subscriber가 되어서 앱의 리스너를 등록하고 푸시 알람을 받는 주체가 됩니다.
1. B Mobile은 앱을 실행하여 채널을 생성합니다.
2. 채널을 기반으로 Subscribe Listener를 등록합니다.
3. 리스너에서는 이벤트(메시지)를 전달받으면 FCM 메시지를 출력할 수 있는 Notifee를 이벤트로 등록해 둡니다.
💡 수신 처리 과정(수신 완료 및 메시지 출력)
- B Mobile에서 대기 상태에 이벤트(메시지)를 받기 위해 리스너를 등록하였습니다. 이 상태에서 A Mobile에서 전송한 FCM 메시지를 수신받으면 이에 따라 등록한 이벤트를 수행합니다.
1. B Mobile은 대기 상태로 있다가 FCM 메시지를 전송받으면 이벤트를 수행합니다.
2. 이벤트로 구성해 두었던 Notifee 라이브러리를 통해 알람을 통해 푸시 메시지를 띄어줍니다.
- MVC는 Model-View-Controller로 애플리케이션을 세 가지의 계층으로 구분한 방법론을 의미합니다.
- 사용자가 처음 페이지를 출력하는 경우 Controller로 요청이 발생하고 Model에서 데이터를 가져와서 그 정보를 바탕으로 시각적 표현인 View를 그려주는 아키텍처 패턴을 의미합니다.
구성 요소
설명
모델(Model)
데이터와 그 데이터를 처리하는 비즈니스 로직을 담당. 데이터를 저장하고, 필요한 데이터를 컨트롤러에게 제공하며, 데이터가 변경 되었을 때 뷰에게 알립니다.
뷰(View)
사용자에게 보여지는 UI 부분을 담당. 사용자가 볼 수 있는 화면을 구성하고, 사용자의 입력을 받아 컨트롤러에게 전달합니다.
컨트롤러(Controller)
사용자의 입력을 처리하고, 그에 따라 모델과 뷰를 업데이트. 사용자의 요청을 해석하고, 적절한 모델의 메서드를 호출하거나, 뷰를 변경하여 사용자에게 응답합니다.
1. MVC 패턴 사용사례: 서버 내에서 템플릿 엔진을 이용한 웹 서버 구축
💡 MVC 패턴 사용사례: 서버 내에서 템플릿 엔진을 이용한 웹 서버 구축
1. Client → ControllerController - 사용자는 클라이언트에 해당하는 브라우저를 접근하여 Controller에게 브라우저 화면을 요청합니다.
2. Controller → Service - Controller에서는 비즈니스 로직을 처리하는 Service 메서드를 호출합니다.
3. Service → DAO - Service에서는 DB 데이터 조작을 위한 처리로 DAO를 호출합니다 4. DAO → DB - DAO는 DB를 접근하여 데이터를 조회에 대한 요청을 합니다
5. DB → DAO - DAO에서는 DB로 받은 데이터를 반환받습니다
6.DAO → Service - DAO에서는 DB 데이터를 가공을 하여 Service로 반환해줍니다.
7. Sevice → Controller - Service에서는 가공된 DB 데이터를 받아서 비즈니스 로직 처리를 한 후 Controller로 반환해줍니다.
8. Controller → View : Server Side Rendering - Controller에서는 데이터를 전달받아 View에 그려주어서 일괄 출력합니다
9. View → Browser - View에서는 Browser로 사용자에게 화면을 제공합니다
10) 블랙보드 패턴(Blackboard Pattern)
💡 블랙보드 패턴 (Blackboard Pattern)
- 명확하게 정의되지 않은 문제이거나 복잡한 문제에 대해 각각의 문제를 '서브 문제'로 분할하고 이 서브 문제들을 여러 개의 '독립적인 시스템'을 통하여 동시에 해결하도록 하는 방식으로 동작하는 패턴입니다.
- 이러한 독립적인 시스템에서 해결된 문제는 '블랙보드'에 해결책을 게시합니다.
블랙보드 패턴의 구성요소
설명
블랙보드(Blackboard)
지식 소스들이 정보를 공유하고 문제를 해결하기 위한 결과를 저장하는 중앙 장소입니다. 모든 시스템이 접근하고 수정 할 수 있습니다.
지식 소스(Knowledge Sources)
문제를 해결하는 데 필요한 전문성을 가진 독립적인 시스템입니다. 각각 지식 소스는 블랙보드에 있는 정보를 사용해서 문제의 일부를 해결하고 결과를 블랙보드에 저장합니다. 이렇게 함으로써 다른 지식 소스들의 결과를 참조하거나 사용할 수 있습니다.
제어 요소(Controller)
문제 해결 과정을 조정합니다. 블랙보드에 있는 정보를 바탕으로 어떤 지식 소스가 다음으로 활동할지 결정하며 문제 해결 과정이 유기적으로 진행 될 수 있도록 합니다.
1. 블랙보드 패턴 사용사례 : 차량 식별 및 추적
💡 블랙보드 패턴 사용사례 : 차량 식별 및 추적 1. 블랙보드 패턴
- 차량 식별 및 추적시스템에서 여러 지식 소스(Knowledge Sources)들이 독립적으로 작동하여 각각의 전문성에 따라 차량을 식별하고 추적 작업을 수행합니다.
2. 지식 소스(Knowledge Sources)
- 하나의 지식 소스는 차량의 번호판을 인식하는 작업을 담당하고 다른 하나는 차량의 모델을 식별하는 작업을 수행하고, 또 다른 하나는 차량의 색상을 식별하는 작업을 각각 수행할 수 있습니다. - 이러한 각각의 지식소스는 자신의 작업 결과를 블랙보드에 저장하며 이 정보는 다른 지식 소스에게 참조되거나 사용될 수 있습니다.
3. 제어요소(Controller)
- 제어요소에서는 모든 과정을 조정합니다. 블랙보드에 저장된 정보를 바탕으로 어떤 지식 소스가 다음으로 활동할지 결정하며 이러한 방식으로 차량 식별 및 추적 작업이 유기적으로 진행될 수 있게 합니다.
- 주어진 언어에 대해 그 언어의 문법을 위한 표현을 정의하고 이 언어로 작성된 문장을 해석하는 해석기(Interpreter) 사용하여 해당 언어로 작성된 문자을 해석하는 아키텍처 패턴을 의미합니다.
- 주로 문법 트리를 구성하고 이 트리를 통해 문장을 해석하는 데 사용됩니다. 각각 문법 규칙은 고유 클래스로 표현되고 문장의 각 부분은 이 클래스의 인스턴스로 표현이 됩니다. - 해당 경우는 문제가 간단할 때 사용하는 것이 가장 좋습니다. 복잡한 문제의 경우, 문법 트리가 너무 크고 복잡해져서 관리하기 어려워질 수 있습니다. 따라서 이 패턴은 간단한 문맥에 대한 문법만 필요한 경우, 예를 들어 간단한 계산기나 정규 표현식 등에 적합합니다. - 이 패턴은 특히 프로그래밍 언어 컴파일러 디자인과 SQL 파싱 같은 언어 기반의 연산에서 사용됩니다.
11) 인터프리터 패턴(Interpreter Pattern)
💡 인터프리터 패턴(Interpreter Pattern)
- 주어진 언어에 대해 그 언어의 문법을 위한 표현을 정의하고 이 언어로 작성된 문장을 해석하는 해석기(Interpreter) 사용하여 해당 언어로 작성된 문자을 해석하는 아키텍처 패턴을 의미합니다.
- 주로 문법 트리를 구성하고 이 트리를 통해 문장을 해석하는 데 사용됩니다. 각각 문법 규칙은 고유 클래스로 표현되고 문장의 각 부분은 이 클래스의 인스턴스로 표현이 됩니다. - 해당 경우는 문제가 간단할 때 사용하는 것이 가장 좋습니다. 복잡한 문제의 경우, 문법 트리가 너무 크고 복잡해져서 관리하기 어려워질 수 있습니다. 따라서 이 패턴은 간단한 문맥에 대한 문법만 필요한 경우, 예를 들어 간단한 계산기나 정규 표현식 등에 적합합니다. - 이 패턴은 특히 프로그래밍 언어 컴파일러 디자인과 SQL 파싱 같은 언어 기반의 연산에서 사용됩니다.
구성요소
설명
추상 표현식 (Abstract Expression)
모든 노드에 대해 공통의 메서드로 추상 표현식을 정의합니다. interpret()라는 메서드를 통해 해석 작업을 수행하는 메서드를 선언합니다.
터미널 표현식(Terminal Expression)
추상 표현식을 상속받아 구현한 클래스로 문법의 ‘가장 작은 단위’를 나타냅니다.
비터미널 표현식(Nonterminal Expression)
추상 표현식을 상속받아 구현한 클래스로 문법의 ‘복잡한 부분’을 나타냅니다. 비터미널 표현식은 다른 표현식을 포함할 수 있습니다.
- 정규식을 구성하는 표현식을 생성합니다. - 이는 터미널 표현식(TerminalExpression)과 비터미널 표현식(NontermianlExpression)의 조합으로 이루어집니다. - 예를 들어, [0-9]+라는 정규식은 '0-9'라는 터미널 표현식과 '+'라는 비터미널 표현식으로 구성될 수 있습니다.
3. 표현식 해석(Expression Interpreter)
- 생성된 표현식을 사용하여 Context 내의 정규식을 해석합니다. - 각 표현식은 자신이 해석할 부분을 해석하고, 결과를 반환합니다.
4. 결과 반환
- 마지막으로, 인터프리터는 해석된 결과를 반환합니다. - 이 결과는 정규식이 매칭되는지 아닌지, 매칭된다면 어떤 부분이 매칭되는지 등의 정보를 포함할 수 있습니다.
1. 인터프리터 패턴 사용사례 : 정규 표현식
💡 인터프리터 패턴 사용사례 : 정규 표현식
1. Expression 클래스 - 추상 클래스로, 모든 표현식이 구현해야 하는 'interpret' 메서드를 정의합니다. - 이 메서드는 주어진 문자열이 표현식에 맞는지 판단합니다.
2. TerminalExpression 클래스 - 'Expression' 클래스를 상속받은 터미널 표현식 클래스입니다. - 이 클래스는 생성자로 받은 문자열이 주어진 컨텍스트에 포함되어 있는지를 판단합니다.
3. OrExpression 클래스 - 'Expression' 클래스를 상속받은 비터미널 표현식 클래스입니다. - 이 클래스는 두 표현식 중 하나라도 주어진 컨텍스트에 맞으면 참을 반환합니다.
4. Client 클래스 - 'Expression' 클래스를 상속받은 표현식들을 생성하고 'interpret' 메서드를 호출하여 결과를 출력하는 클라이언트 클래스입니다. - 여기서는 '[0-9]' 또는 '+'가 "123+456"에 포함되어 있는지를 확인합니다.
// 추상 표현식
public abstract class Expression {
public abstract boolean interpret(String context);
}
// 터미널 표현식
public class TerminalExpression extends Expression {
private String data;
public TerminalExpression(String data){
this.data = data;
}
public boolean interpret(String context){
if(context.contains(data)){
return true;
}
return false;
}
}
// 비터미널 표현식
public class OrExpression extends Expression {
private Expression expr1 = null;
private Expression expr2 = null;
public OrExpression(Expression expr1, Expression expr2) {
this.expr1 = expr1;
this.expr2 = expr2;
}
public boolean interpret(String context) {
return expr1.interpret(context) || expr2.interpret(context);
}
}
// 클라이언트
public class Client {
public static void main(String[] args) {
Expression isNumber = new TerminalExpression("[0-9]");
Expression isPlus = new TerminalExpression("+");
Expression isNumberPlus = new OrExpression(isNumber, isPlus);
System.out.println("Context: 123+456");
System.out.println("Interpreter Result: " + isNumberPlus.interpret("123+456"));
}
}