티스토리 뷰
728x90
어댑터 패턴
설명:
어댑터 패턴은 호환되지 않는 인터페이스를 연결하여 기존 클래스를 새 시스템에서 사용할 수 있게 합니다. 예를 들어, 레거시 시스템의 오래된 API를 최신 시스템과 통합할 때 유용합니다. 이는 기존 코드를 수정하지 않고 새로운 인터페이스를 제공하여 호환성을 확보합니다.
어댑터 패턴은 호환되지 않는 인터페이스를 연결하여 기존 클래스를 새 시스템에서 사용할 수 있게 합니다. 예를 들어, 레거시 시스템의 오래된 API를 최신 시스템과 통합할 때 유용합니다. 이는 기존 코드를 수정하지 않고 새로운 인터페이스를 제공하여 호환성을 확보합니다.
사용처:
-
레거시 시스템과 새 코드 통합, 예: 오래된 API와 최신 시스템 연결.
자바 예제:
// 기존 클래스 (Adaptee)
class OldPrinter {
public void printMessage(String msg) {
System.out.println("Old Printer: " + msg);
}
}
// 새 인터페이스 (Target)
interface TextDisplay {
void displayText(String text);
}
// 어댑터 (Adapter)
class PrinterAdapter implements TextDisplay {
private OldPrinter printer;
public PrinterAdapter(OldPrinter printer) {
this.printer = printer;
}
@Override
public void displayText(String text) {
printer.printMessage(text);
}
}
// 사용 예
public class Main {
public static void main(String[] args) {
OldPrinter oldPrinter = new OldPrinter();
TextDisplay adapter = new PrinterAdapter(oldPrinter);
adapter.displayText("Hello, World!"); // 출력: Old Printer: Hello, World!
}
}
브리지 패턴
설명:
브리지 패턴은 추상화와 구현을 분리하여 둘을 독립적으로 변형할 수 있게 합니다. 예를 들어, GUI 시스템에서 버튼을 렌더링하는 방식(예: SVG, Canvas)을 변경하더라도 버튼 클래스는 영향을 받지 않습니다. 이는 플랫폼 독립성을 높이는 데 유용합니다.
브리지 패턴은 추상화와 구현을 분리하여 둘을 독립적으로 변형할 수 있게 합니다. 예를 들어, GUI 시스템에서 버튼을 렌더링하는 방식(예: SVG, Canvas)을 변경하더라도 버튼 클래스는 영향을 받지 않습니다. 이는 플랫폼 독립성을 높이는 데 유용합니다.
사용처:
-
디바이스 드라이버, 예: 프린터 인터페이스와 하드웨어 구현 분리.
자바 예제:
// 추상화 (Abstraction)
abstract class Shape {
protected Renderer renderer;
public Shape(Renderer renderer) {
this.renderer = renderer;
}
public abstract void draw();
}
// 구체적인 추상화 (Concrete Abstraction)
class Circle extends Shape {
public Circle(Renderer renderer) {
super(renderer);
}
@Override
public void draw() {
renderer.drawCircle();
}
}
// 구현 인터페이스 (Implementor)
interface Renderer {
void drawCircle();
}
// 구체적인 구현 (Concrete Implementor)
class SVGRenderer implements Renderer {
@Override
public void drawCircle() {
System.out.println("Drawing circle in SVG");
}
}
class CanvasRenderer implements Renderer {
@Override
public void drawCircle() {
System.out.println("Drawing circle in Canvas");
}
}
// 사용 예
public class Main {
public static void main(String[] args) {
Shape circle = new Circle(new SVGRenderer());
circle.draw(); // 출력: Drawing circle in SVG
circle = new Circle(new CanvasRenderer());
circle.draw(); // 출력: Drawing circle in Canvas
}
}
컴포지트 패턴
설명:
컴포지트 패턴은 부분-전체 계층 구조를 표현하여 개별 객체와 객체 집합을 동일하게 다룰 수 있게 합니다. 예를 들어, 파일 시스템에서 디렉토리(디렉토리와 파일 포함)와 파일을 동일한 방식으로 처리할 수 있습니다. 이는 계층적 구조를 쉽게 관리하게 합니다.
컴포지트 패턴은 부분-전체 계층 구조를 표현하여 개별 객체와 객체 집합을 동일하게 다룰 수 있게 합니다. 예를 들어, 파일 시스템에서 디렉토리(디렉토리와 파일 포함)와 파일을 동일한 방식으로 처리할 수 있습니다. 이는 계층적 구조를 쉽게 관리하게 합니다.
사용처:
-
파일 시스템, 예: 디렉토리와 파일의 계층적 구조.
자바 예제:
import java.util.ArrayList;
import java.util.List;
// 컴포넌트 인터페이스 (Component)
interface FileSystemItem {
void print();
}
// 리프 노드 (Leaf)
class File implements FileSystemItem {
private String name;
public File(String name) {
this.name = name;
}
@Override
public void print() {
System.out.println("File: " + name);
}
}
// 컴포지트 노드 (Composite)
class Directory implements FileSystemItem {
private String name;
private List<FileSystemItem> items;
public Directory(String name) {
this.name = name;
this.items = new ArrayList<>();
}
public void addItem(FileSystemItem item) {
items.add(item);
}
@Override
public void print() {
System.out.println("Directory: " + name);
for (FileSystemItem item : items) {
item.print();
}
}
}
// 사용 예
public class Main {
public static void main(String[] args) {
File file1 = new File("file1.txt");
File file2 = new File("file2.txt");
Directory subDir = new Directory("subdir");
subDir.addItem(file2);
Directory root = new Directory("root");
root.addItem(file1);
root.addItem(subDir);
root.print();
// 출력:
// Directory: root
// File: file1.txt
// Directory: subdir
// File: file2.txt
}
}
데코레이터 패턴
설명:
데코레이터 패턴은 객체에 동적으로 새로운 책임을 추가할 수 있게 합니다. 기존 객체를 감싸는 데코레이터를 통해 기능을 확장하며, 예를 들어 데이터 스트림에 암호화나 압축을 추가할 수 있습니다. 이는 기존 클래스를 수정하지 않고 기능을 확장할 수 있게 합니다.
데코레이터 패턴은 객체에 동적으로 새로운 책임을 추가할 수 있게 합니다. 기존 객체를 감싸는 데코레이터를 통해 기능을 확장하며, 예를 들어 데이터 스트림에 암호화나 압축을 추가할 수 있습니다. 이는 기존 클래스를 수정하지 않고 기능을 확장할 수 있게 합니다.
사용처:
-
데이터 스트림에 암호화 또는 압축 추가, 예: 네트워크 데이터 보호.
자바 예제:
// 컴포넌트 인터페이스 (Component)
interface Stream {
void write(String data);
}
// 구체적인 컴포넌트 (Concrete Component)
class BasicStream implements Stream {
@Override
public void write(String data) {
System.out.println("Writing: " + data);
}
}
// 데코레이터 추상 클래스 (Decorator)
abstract class StreamDecorator implements Stream {
protected Stream stream;
public StreamDecorator(Stream stream) {
this.stream = stream;
}
@Override
public void write(String data) {
stream.write(data);
}
}
// 구체적인 데코레이터 (Concrete Decorator)
class EncryptedStream extends StreamDecorator {
public EncryptedStream(Stream stream) {
super(stream);
}
@Override
public void write(String data) {
// 암호화 시뮬레이션
String encrypted = "Encrypted_" + data;
super.write(encrypted);
}
}
// 사용 예
public class Main {
public static void main(String[] args) {
Stream stream = new BasicStream();
Stream encryptedStream = new EncryptedStream(stream);
encryptedStream.write("Hello, World!"); // 출력: Writing: Encrypted_Hello, World!
}
}
파사드 패턴
설명:
파사드 패턴은 복잡한 서브시스템에 통합된 인터페이스를 제공하여 클라이언트가 쉽게 사용할 수 있게 합니다. 예를 들어, 데이터베이스 연결 풀을 관리하는 복잡한 과정을 단순화하여 클라이언트가 쿼리만 실행하면 됩니다. 이는 시스템의 복잡성을 숨기고 사용성을 높입니다.
파사드 패턴은 복잡한 서브시스템에 통합된 인터페이스를 제공하여 클라이언트가 쉽게 사용할 수 있게 합니다. 예를 들어, 데이터베이스 연결 풀을 관리하는 복잡한 과정을 단순화하여 클라이언트가 쿼리만 실행하면 됩니다. 이는 시스템의 복잡성을 숨기고 사용성을 높입니다.
사용처:
-
데이터베이스 연결 풀, 예: 연결 관리 세부 사항 숨김.
자바 예제:
// 서브시스템 클래스
class DatabaseConnection {
public static Connection getConnection() {
// 연결 가져오기 시뮬레이션
return new Connection();
}
}
class Connection {
// 연결 메서드 시뮬레이션
public void executeQuery(String query) {
System.out.println("Executing query: " + query);
}
}
// 파사드 클래스
class DatabaseFacade {
private Connection connection;
public DatabaseFacade() {
connection = DatabaseConnection.getConnection();
}
public void performQuery(String query) {
connection.executeQuery(query);
}
}
// 사용 예
public class Main {
public static void main(String[] args) {
DatabaseFacade facade = new DatabaseFacade();
facade.performQuery("SELECT * FROM table"); // 출력: Executing query: SELECT * FROM table
}
}
플라이웨이트 패턴
설명:
플라이웨이트 패턴은 메모리 효율성을 높이기 위해 객체를 공유하여 동일한 데이터를 여러 객체가 재사용하게 합니다. 예를 들어, 텍스트 편집기에서 여러 문자가 동일한 폰트와 스타일을 공유할 수 있습니다. 이는 메모리 사용량을 줄이는 데 유용합니다.
플라이웨이트 패턴은 메모리 효율성을 높이기 위해 객체를 공유하여 동일한 데이터를 여러 객체가 재사용하게 합니다. 예를 들어, 텍스트 편집기에서 여러 문자가 동일한 폰트와 스타일을 공유할 수 있습니다. 이는 메모리 사용량을 줄이는 데 유용합니다.
사용처:
-
텍스트 편집기, 예: 문자열 객체 공유.
자바 예제:
import java.util.HashMap;
import java.util.Map;
// 플라이웨이트 인터페이스
interface Character {
void display(char c);
}
// 구체적인 플라이웨이트
class CharacterImpl implements Character {
private String font;
private String style;
public CharacterImpl(String font, String style) {
this.font = font;
this.style = style;
}
@Override
public void display(char c) {
System.out.println("Displaying '" + c + "' with font " + font + " and style " + style);
}
}
// 플라이웨이트 팩토리
class CharacterFactory {
private Map<String, Character> characters = new HashMap<>();
public Character getCharacter(String font, String style) {
String key = font.trim() + "_" + style;
if (!characters.containsKey(key)) {
characters.put(key, new CharacterImpl(font, style));
}
return characters.get(key);
}
}
// 사용 예
public class Main {
public static void main(String[] args) {
CharacterFactory factory = new CharacterFactory();
Character charA = factory.getCharacter("Arial", "bold");
charA.display('A'); // 출력: Displaying 'A' with font Arial and style bold
Character charB = factory.getCharacter("Arial", "bold");
charB.display('B'); // 출력: Displaying 'B' with font Arial and style bold
// charA와 charB는 동일한 플라이웨이트 객체를 공유
}
}
프록시 패턴
설명:
프록시 패턴은 다른 객체에 대한 대리자나 플레이스홀더를 제공하여 객체 접근을 제어합니다. 예를 들어, 이미지를 로드하는 데 시간이 오래 걸리면 프록시를 통해 이미지를 필요할 때 로드할 수 있습니다. 이는 보안 체크, 지연 로드, 원격 객체 접근 등에 유용합니다.
프록시 패턴은 다른 객체에 대한 대리자나 플레이스홀더를 제공하여 객체 접근을 제어합니다. 예를 들어, 이미지를 로드하는 데 시간이 오래 걸리면 프록시를 통해 이미지를 필요할 때 로드할 수 있습니다. 이는 보안 체크, 지연 로드, 원격 객체 접근 등에 유용합니다.
사용처:
-
네트워크를 통한 원격 객체 접근, 예: 보안 체크를 위한 보호 프록시.
자바 예제:
// 주제 인터페이스 (Subject)
interface Displayable {
void display();
}
// 실제 주제 (Real Subject)
class Image implements Displayable {
private String filename;
public Image(String filename) {
this.filename = filename;
loadFromDisk();
}
private void loadFromDisk() {
System.out.println("Loading " + filename);
}
@Override
public void display() {
System.out.println("Displaying " + filename);
}
}
// 프록시 (Proxy)
class ImageProxy implements Displayable {
private String filename;
private Image realImage;
public ImageProxy(String filename) {
this.filename = filename;
}
@Override
public void display() {
if (realImage == null) {
realImage = new Image(filename);
}
realImage.display();
}
}
// 사용 예
public class Main {
public static void main(String[] args) {
Displayable proxy = new ImageProxy("image.jpg");
proxy.display(); // 출력: Loading image.jpg, Displaying image.jpg
proxy.display(); // 출력: Displaying image.jpg (재로딩 없음)
}
}
추가 고려사항
이러한 패턴들은 단순히 코드 작성 도구가 아니라, 개발자 간 커뮤니케이션을 용이하게 하는 공통 언어를 제공합니다. 이는 팀 협업을 강화하고, 코드의 가독성과 유지보수성을 높이는 데 기여합니다. 또한, 패턴은 시간이 지남에 따라 개선되며, 새로운 패턴(예: 동시성 패턴)도 등장하고 있습니다. 그러나 모든 상황에 적합하지 않을 수 있으며, 과도한 사용은 코드 복잡성을 증가시킬 수 있습니다.
728x90
'프로그래밍 > 디자인패턴' 카테고리의 다른 글
창조 패턴(Creational Patterns) 자바 예제 설명 (1) | 2025.02.25 |
---|
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- generated_body()
- 코틀린
- cqrs
- 타입 안전성
- 일급 객체
- Java
- method Area
- 스프링부트
- react.js
- MCP
- unreal engjin
- 자바
- ai통합
- 카프카 개념
- vite
- 도커
- 스브링부트
- model context protocol
- Stack Area
- 디자인패턴
- 코프링
- JVM
- RESTfull
- Heap Area
- JAVA 프로그래밍
- 언리얼엔진5
- 언리얼엔진
- springai
- redis
- First-class citizen
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
글 보관함