39. 자바와 디자인 패턴
39.1. 디자인 패턴 개요
디자인 패턴(Design Pattern)은 소프트웨어 개발에서 특정 문제를 해결하는 데 효과적인 설계 방식으로, 재사용 가능한 해결책을 제공합니다. 디자인 패턴은 크게 생성(Creational), 구조(Structural), 행위(Behavioral) 패턴으로 나눌 수 있습니다.
39.2. 생성 패턴 (Singleton, Factory, Builder 등)
생성 패턴은 객체 생성에 관련된 패턴으로, 객체 생성 과정을 캡슐화하거나 더 유연한 객체 생성 방식을 제공합니다.
- Singleton 패턴: 클래스의 인스턴스가 단 하나만 존재하도록 보장하는 패턴입니다.
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
- Factory 패턴: 객체 생성 로직을 별도의 클래스로 분리하여 캡슐화하는 패턴입니다.
interface Animal {
void speak();
}
class Dog implements Animal {
public void speak() {
System.out.println("Woof!");
}
}
class Cat implements Animal {
public void speak() {
System.out.println("Meow!");
}
}
class AnimalFactory {
public static Animal createAnimal(String type) {
if (type.equalsIgnoreCase("Dog")) {
return new Dog();
} else if (type.equalsIgnoreCase("Cat")) {
return new Cat();
}
return null;
}
}
public class FactoryExample {
public static void main(String[] args) {
Animal dog = AnimalFactory.createAnimal("Dog");
dog.speak();
Animal cat = AnimalFactory.createAnimal("Cat");
cat.speak();
}
}
- Builder 패턴: 복잡한 객체 생성 과정을 단계별로 나누어 구현하는 패턴입니다.
class Car {
private String make;
private String model;
private int year;
private Car(Builder builder) {
this.make = builder.make;
this.model = builder.model;
this.year = builder.year;
}
public static class Builder {
private String make;
private String model;
private int year;
public Builder setMake(String make) {
this.make = make;
return this;
}
public Builder setModel(String model) {
this.model = model;
return this;
}
public Builder setYear(int year) {
this.year = year;
return this;
}
public Car build() {
return new Car(this);
}
}
}
public class BuilderExample {
public static void main(String[] args) {
Car car = new Car.Builder()
.setMake("Toyota")
.setModel("Camry")
.setYear(2020)
.build();
}
}
39.3. 구조 패턴 (Adapter, Decorator, Proxy 등)
구조 패턴은 클래스나 객체들의 구조를 조직하는 패턴으로, 클래스와 객체의 구성을 통해 더 큰 구조를 만들거나 유연성을 제공합니다.
- Adapter 패턴: 서로 다른 인터페이스를 갖는 클래스들이 함께 작동할 수 있도록 인터페이스를 변환하는 패턴입니다.
interface MediaPlayer {
void play(String fileType, String fileName);
}
interface AdvancedMediaPlayer {
void playVlc(String fileName);
void playMp4(String fileName);
}
class VlcPlayer implements AdvancedMediaPlayer {
public void playVlc(String fileName) {
System.out.println("Playing vlc file. Name: " + fileName);
}
public void playMp4(String fileName) {
// Do nothing
}
}
class Mp4Player implements AdvancedMediaPlayer {
public void playVlc(String fileName) {
// Do nothing
}
public void playMp4(String fileName) {
System.out.println("Playing mp4 file. Name: " + fileName);
}
}
class MediaAdapter implements MediaPlayer {
private AdvancedMediaPlayer advancedMediaPlayer;
public MediaAdapter(String fileType) {
if (fileType.equalsIgnoreCase("vlc")) {
advancedMediaPlayer = new VlcPlayer();
} else if (fileType.equalsIgnoreCase("mp4")) {
advancedMediaPlayer = new Mp4Player();
}
}
public void play(String fileType, String fileName) {
if (fileType.equalsIgnoreCase("vlc")) {
advancedMediaPlayer.playVlc(fileName);
} else if (fileType.equalsIgnoreCase("mp4")) {
advancedMediaPlayer.playMp4(fileName);
}
}
}
public class AdapterExample {
public static void main(String[] args) {
MediaPlayer mediaPlayer = new MediaAdapter("vlc");
mediaPlayer.play("vlc", "example.vlc");
mediaPlayer = new MediaAdapter("mp4");
mediaPlayer.play("mp4", "example.mp4");
}
}
- Decorator 패턴: 기존 객체에 동적으로 새로운 기능을 추가하는 패턴입니다.
interface Coffee {
double cost();
}
class SimpleCoffee implements Coffee {
public double cost() {
return 2.00;
}
}
abstract class CoffeeDecorator implements Coffee {
protected Coffee decoratedCoffee;
public CoffeeDecorator(Coffee decoratedCoffee) {
this.decoratedCoffee = decoratedCoffee;
}
public double cost() {
return decoratedCoffee.cost();
}
}
class Milk extends CoffeeDecorator {
public Milk(Coffee decoratedCoffee) {
super(decoratedCoffee);
}
public double cost() {
return super.cost() + 0.50;
}
}
public class DecoratorExample {
public static void main(String[] args) {
Coffee coffee = new SimpleCoffee();
coffee = new Milk(coffee);
System.out.println("Total cost: " + coffee.cost());
}
}
- Proxy 패턴: 실제 객체에 대한 참조를 제공하여 객체의 일부 기능을 대신 수행하는 패턴입니다.
interface Image {
void display();
}
class RealImage implements Image {
private String fileName;
public RealImage(String fileName) {
this.fileName = fileName;
loadFromDisk(fileName);
}
private void loadFromDisk(String fileName) {
System.out.println("Loading " + fileName);
}
public void display() {
System.out.println("Displaying " + fileName);
}
}
class ProxyImage implements Image {
private RealImage realImage;
private String fileName;
public ProxyImage(String fileName) {
this.fileName = fileName;
}
public void display() {
if (realImage == null) {
realImage = new RealImage(fileName);
}
realImage.display();
}
}
public class ProxyExample {
public static void main(String[] args) {
Image image = new ProxyImage("example.jpg");
// 이미지 로드 후 출력
image.display();
System.out.println("");
// 이미지 로드 없이 출력
image.display();
}
}
39.4. 행위 패턴 (Observer, Strategy, State 등)
행위 패턴은 객체들 사이의 알고리즘, 상호작용, 책임 분배 등을 정의하는 패턴입니다.
- Observer 패턴: 객체 상태 변경 시 관련 객체들에게 알림을 전달하는 패턴입니다.
import java.util.ArrayList;
import java.util.List;
interface Observer {
void update(String message);
}
class Subscriber implements Observer {
private String name;
public Subscriber(String name) {
this.name = name;
}
public void update(String message) {
System.out.println(name + " received: " + message);
}
}
class Channel {
private List<Observer> subscribers = new ArrayList<>();
public void subscribe(Observer subscriber) {
subscribers.add(subscriber);
}
public void unsubscribe(Observer subscriber) {
subscribers.remove(subscriber);
}
public void notifySubscribers(String message) {
for (Observer subscriber : subscribers) {
subscriber.update(message);
}
}
}
public class ObserverExample {
public static void main(String[] args) {
Channel channel = new Channel();
Subscriber subscriber1 = new Subscriber("Subscriber 1");
Subscriber subscriber2 = new Subscriber("Subscriber 2");
channel.subscribe(subscriber1);
channel.subscribe(subscriber2);
channel.notifySubscribers("New video uploaded!");
}
}
- Strategy 패턴: 알고리즘을 캡슐화하여 런타임에 동적으로 알고리즘을 변경할 수 있는 패턴입니다.
interface SortingStrategy {
void sort(int[] numbers);
}
class BubbleSortStrategy implements SortingStrategy {
public void sort(int[] numbers) {
// Bubble sort implementation
}
}
class QuickSortStrategy implements SortingStrategy {
public void sort(int[] numbers) {
// Quick sort implementation
}
}
class Sorter {
private SortingStrategy strategy;
public void setStrategy(SortingStrategy strategy) {
this.strategy = strategy;
}
public void sort(int[] numbers) {
strategy.sort(numbers);
}
}
public class StrategyExample {
public static void main(String[] args) {
Sorter sorter = new Sorter();
sorter.setStrategy(new BubbleSortStrategy());
sorter.sort(new int[]{3, 1, 4, 1, 5, 9});
sorter.setStrategy(new QuickSortStrategy());
sorter.sort(new int[]{3, 1, 4, 1, 5, 9});
}
}
- State 패턴: 객체의 내부 상태에 따라 동작을 변경하는 패턴입니다.
interface State {
void doAction(Context context);
}
class StartState implements State {
public void doAction(Context context) {
System.out.println("Start state");
context.setState(this);
}
}
class EndState implements State {
public void doAction(Context context) {
System.out.println("End state");
context.setState(this);
}
}
class Context {
private State state;
public Context() {
state = null;
}
public void setState(State state) {
this.state = state;
}
public State getState() {
return state;
}
}
public class StateExample {
public static void main(String[] args) {
Context context = new Context();
StartState startState = new StartState();
startState.doAction(context);
System.out.println("Current state: " + context.getState().getClass().getSimpleName());
EndState endState = new EndState();
endState.doAction(context);
System.out.println("Current state: " + context.getState().getClass().getSimpleName());
}
}
이렇게 디자인 패턴을 활용하면 코드의 유지보수성, 확장성, 재사용성이 향상됩니다. 자바 초보자라도 이러한 디자인 패턴을 이해하고 적용하면서 실력을 향상할 수 있습니다.
반응형
'GD's IT Lectures : 기초부터 시리즈 > 자바(JAVA) 기초부터 ~' 카테고리의 다른 글
[자바(JAVA)] 자바와 암호화 (0) | 2023.04.30 |
---|---|
[자바(JAVA)] 자바와 네트워킹 (0) | 2023.04.30 |
[자바(JAVA)] 자바의 동시성과 병렬 처리 (0) | 2023.04.30 |
[자바(JAVA)] 자바와 데이터베이스 (0) | 2023.04.30 |
[자바(JAVA)] 자바와 블록체인 (0) | 2023.04.30 |
댓글