객체지향 디자인 패턴 2편

Facade, Template-method, Decorator, Factory-method, Abstract-factory-method, Mediator, Composite

지난 번 여섯가지 패턴들에 이어
이번 영상에서는 일곱가지 패턴들을 더 알아봅니다.


패턴 분:초
Facade 패턴 00:10
Template-method 패턴 01:32
Decorator 04:07 패턴
Factory-method 패턴 06:07
Abstract-factory-method 패턴 09:00
Mediator 패턴 09:38
Composite 패턴 12:09

❗각 패턴의 내용들이 서로 연결된 부분이 있기 때문에
가능한 전체 영상을 시청할 것을 권장합니다.

예제 코드들을 아래에서 각각 확인하세요 😊


Facade 패턴

패턴이란 인식 없이 널리 사용되고 있는,
가장 단순하다고 할 수 있는 패턴입니다.

FacadePattern.java

import java.util.Map; public class FacadePattern { public static void main(String[] args) { double[] myGeoLoc = new GeoLocation().getGeoLoc(); InternetConnection conn = new InternetConnection(); conn.connect(); String data = conn.getData("https://주소_API_URL", myGeoLoc); conn.disconnect(); Map<String, Object> address = new Json().parse(data); System.out.println(address.get("address")); // 서울시 개발구 객체동 new MyLocFacade().printMyAddress(); } }

GeoLocation.java

public class GeoLocation { public double[] getGeoLoc() { double[] geoLoc = {0, 0}; return geoLoc; } }

InternetConnection.java

public class InternetConnection { public void connect() {}; public String getData(String url, Object param) { return ""; } public void disconnect() {}; }

Json.java

import java.util.HashMap; import java.util.Map; public class Json { public Map<String, Object> parse(String str) { Map<String, Object> result = new HashMap<>(); result.put("address", "서울시 개발구 객체동"); return result; } }

MyLocFacade.java

import java.util.Map; public class MyLocFacade { public void printMyAddress () { double[] myGeoLoc = new GeoLocation().getGeoLoc(); InternetConnection conn = new InternetConnection(); conn.connect(); String data = conn.getData("https://주소_API_URL", myGeoLoc); conn.disconnect(); Map<String, Object> address = new Json().parse(data); System.out.println(address.get("address")); } }

Template method 패턴

전체 절차는 정해져 있지만
세부 절차를 자식 클래스로 다양화할 수 있는 패턴입니다.

TemplateExample.java

public class TemplateExample { public static void main(String[] args) { new NaverMapView().initMap(); new KakaoMapView().initMap(); } }

MapView.java

public abstract class MapView { protected abstract void connectMapServer(); protected abstract void showMapOnScreen(); protected abstract void moveToCurrentLocation(); public void initMap () { connectMapServer(); showMapOnScreen(); moveToCurrentLocation(); } }

NaverMapView.java

public class NaverMapView extends MapView { @Override protected void connectMapServer() { System.out.println("네이버 지도 서버에 연결"); }; @Override protected void showMapOnScreen() { System.out.println("네이버 지도를 보여줌"); }; @Override protected void moveToCurrentLocation() { System.out.println("네이버 지도에서 현 좌표로 이동"); }; }

KakaoMapView.java

public class KakaoMapView extends MapView { @Override protected void connectMapServer() { System.out.println("카카오 지도 서버에 연결"); }; @Override protected void showMapOnScreen() { System.out.println("카카오 지도를 보여줌"); }; @Override protected void moveToCurrentLocation() { System.out.println("카카오 지도에서 현 좌표로 이동"); }; }

데코레이터 패턴

객체를 다른 객체에 넣어 기능을 추가하는 방식
바로 이해하기 낯설지만 잘 활용하면 정말 유용한 패턴입니다.

DecoratorPattern.java

public class DecoratorPattern { public static void main(String[] args) { new XWingFighter().attack(); // 탄환 발사 new LaserDecorator(new XWingFighter()).attack(); // 탄환 발사 // 레이저 발사 new PlasmaDecorator( new MissileDecorator( new LaserDecorator( new XWingFighter() ))).attack(); // 탄환 발사 // 레이저 발사 // 미사일 발사 // 플라즈마 발사 } }

Fighter.java

public interface Fighter { public void attack (); }

XWingFighter.java

public class XWingFighter implements Fighter { @Override public void attack () { System.out.println("탄환 발사"); } }

FighterDecorator.java

public abstract class FighterDecorator implements Fighter { private Fighter decoratedFighter; public FighterDecorator(Fighter _decoratedFighter) { decoratedFighter = _decoratedFighter; } @Override public void attack () { decoratedFighter.attack(); } }

LaserDecorator.java

public class LaserDecorator extends FighterDecorator { public LaserDecorator (Fighter _decoratedFighter) { super(_decoratedFighter); } @Override public void attack () { super.attack(); System.out.println("레이저 발사"); } }

MissileDecorator.java

public class MissileDecorator extends FighterDecorator { public MissileDecorator (Fighter _decoratedFighter) { super(_decoratedFighter); } @Override public void attack () { super.attack(); System.out.println("미사일 발사"); } }

PlasmaDecorator.java

public class PlasmaDecorator extends FighterDecorator { public PlasmaDecorator (Fighter _decoratedFighter) { super(_decoratedFighter); } @Override public void attack () { super.attack(); System.out.println("플라즈마 발사"); } }

Factory method 패턴

클래스를 선택하고 객체를 고르는 일은 이제 공장에 맡기세요!

기본 예제

FactoryMethod.java

class FactoryMethod { public static void main(String[] args) { new Console().withoutFactory(); new Console().withFactory(); } }

Component.java

abstract class Component { protected abstract String getCompName (); public Component () { System.out.println(this.getCompName() + " 생성"); } } class Button extends Component { @Override protected String getCompName() { return "버튼"; } } class Switch extends Component { @Override protected String getCompName() { return "스위치"; } } class Dropdown extends Component { @Override protected String getCompName() { return "드랍다운"; } }

CompFactory.java

class CompFactory { public Component getComp (Usage usage) { if (usage == Usage.PRESS) { return new Button(); } else if (usage == Usage.TOGGLE) { return new Switch(); } else { return new Dropdown(); } } }

Console.jafa

class Console { private CompFactory compFactory = new CompFactory(); Component comp1; Component comp2; Component comp3; void withoutFactory () { comp1 = new Button(); comp2 = new Switch(); comp3 = new Dropdown(); } void withFactory () { comp1 = compFactory.getComp(Usage.PRESS); comp2 = compFactory.getComp(Usage.TOGGLE); comp3 = compFactory.getComp(Usage.EXPAND); } } enum Usage { PRESS, TOGGLE, EXPAND }

Decorator 패턴 예제에 적용

FighterFactory.java

public class FighterFactory { public Fighter getFighter(boolean laser, boolean missile, boolean plasma) { Fighter fighter = new XWingFighter(); if (laser) fighter = new LaserDecorator(fighter); if (missile) fighter = new MissileDecorator(fighter); if (plasma) fighter = new PlasmaDecorator(fighter); return fighter; } }

FactoryDecorator.java

public class FactoryDecorator { public static void main(String[] args) { FighterFactory factory = new FighterFactory(); factory.getFighter(false, false, false).attack(); // 탄환 발사 factory.getFighter(true, false, true).attack(); // 탄환 발사 // 레이저 발사 // 플라즈마 발사 factory.getFighter(true, true, false).attack(); // 탄환 발사 // 레이저 발사 // 미사일 발사 factory.getFighter(true, true, true).attack(); // 탄환 발사 // 레이저 발사 // 미사일 발사 // 플라즈마 발사 } }

Abstract factory 패턴

공장을 추상화하여 다양화하기 위한 패턴입니다.

FactoryMethod.java

class FactoryMethod { public static void main(String[] args) { new Console().withFactory(); } }

Component.java

abstract class Component { protected abstract String getCompName (); public Component () { System.out.println(this.getCompName() + " 생성"); } } class LightButton extends Component { @Override protected String getCompName() { return "라이트 버튼"; } } class DarkButton extends Component { @Override protected String getCompName() { return "다크 버튼"; } } class LightSwitch extends Component { @Override protected String getCompName() { return "라이트 스위치"; } } class DarkSwitch extends Component { @Override protected String getCompName() { return "다크 스위치"; } } class LightDropdown extends Component { @Override protected String getCompName() { return "라이트 드랍다운"; } } class DarkDropdown extends Component { @Override protected String getCompName() { return "다크 드랍다운"; } }

CompFactory.java

interface CompFactory { public Component getComp (Usage usage); } // 라이트 테마 공장 class LightCompFactory implements CompFactory { @Override public Component getComp (Usage usage) { if (usage == Usage.PRESS) { return new LightButton(); } else if (usage == Usage.TOGGLE) { return new LightSwitch(); } else { return new LightDropdown(); } } } // 다크 테마 공장 class DarkCompFactory implements CompFactory { @Override public Component getComp (Usage usage) { if (usage == Usage.PRESS) { return new DarkButton(); } else if (usage == Usage.TOGGLE) { return new DarkSwitch(); } else { return new DarkDropdown(); } } }

Console.java

class Console { private CompFactory lightCompFactory = new LightCompFactory(); private CompFactory darkCompFactory = new DarkCompFactory(); Component comp1; Component comp2; Component comp3; void withFactory () { comp1 = lightCompFactory.getComp(Usage.PRESS); comp2 = lightCompFactory.getComp(Usage.TOGGLE); comp3 = lightCompFactory.getComp(Usage.EXPAND); // 라이트 버튼 생성 // 라이트 스위치 생성 // 라이트 드랍다운 생성 comp1 = darkCompFactory.getComp(Usage.PRESS); comp2 = darkCompFactory.getComp(Usage.TOGGLE); comp3 = darkCompFactory.getComp(Usage.EXPAND); // 다크 버튼 생성 // 다크 스위치 생성 // 다크 드랍다운 생성 } } enum Usage { PRESS, TOGGLE, EXPAND }

미디에이터 패턴

한 클래스에서의 이벤트가 연결된 다른 클래스의 객체에 영향을 미칠 때
미디에이터 패턴으로 효율적인 설계를 할 수 있습니다.

MediatorPattern.java

public class MediatorPattern { public static void main(String[] args) { ModeSwitch modeSwitch = new ModeSwitch(); ModeMediator modeMediator = new ModeMediator(); modeSwitch.setModeMediator(modeMediator); modeMediator.addListener(new ListView()); modeMediator.addListener(new GalleryView()); modeMediator.addListener(new DataDownloader()); modeSwitch.toggleMode(); // 리스트뷰 감춤 // 갤러리뷰 보여줌 // 갤러리뷰용 데이터 다운로드 modeSwitch.toggleMode(); // 리스트뷰 보여줌 // 갤러리뷰 감춤 // 리스트뷰용 데이터 다운로드 } }

ModeSwitch.java

public class ModeSwitch { Mode mode = Mode.LIST; ModeMediator modeMediator; public void setModeMediator (ModeMediator _modeMediator) { modeMediator = _modeMediator; } public void toggleMode () { mode = mode == Mode.LIST ? Mode.GALLERY : Mode.LIST; if (modeMediator != null) { modeMediator.onModeChange(mode); } } } enum Mode { LIST, GALLERY }

ModeListener.java

public interface ModeListener { public void onModeChange (Mode mode); } class ListView implements ModeListener { @Override public void onModeChange(Mode mode) { System.out.println( "리스트뷰 " + (mode == Mode.LIST ? "보여줌" : "감춤") ); } } class GalleryView implements ModeListener { @Override public void onModeChange(Mode mode) { System.out.println( "갤러리뷰 " + (mode == Mode.GALLERY ? "보여줌" : "감춤") ); } } class DataDownloader implements ModeListener { @Override public void onModeChange(Mode mode) { System.out.println( (mode == Mode.LIST ? "리스트" : "갤러리") + "뷰용 데이터 다운로드"); } }

ModeMediator.java

import java.util.ArrayList; public class ModeMediator { ArrayList<ModeListener> listeners = new ArrayList<>(); public void addListener(ModeListener listener) { listeners.add(listener); } public void onModeChange (Mode mode) { for (ModeListener listener : listeners) { listener.onModeChange(mode); } } }

Composite 패턴

특정 클래스의 객체들을 트리 관계로 다루고
포함하는 객체와 포함되는 객체를 같은 인터페이스로
다룰 수 있도록 하는 패턴입니다.

FileSystem.java

import java.util.ArrayList; public interface FileSystem { public int getSize(); public void remove(); } class File implements FileSystem { private String name; private int size; public File (String _name, int _size) { name = _name; size = _size; } @Override public int getSize() { System.out.println(name + "파일 크기 : " + size); return size; } @Override public void remove() { System.out.println(name + " 파일 삭제"); } } class Folder implements FileSystem { private String name; private ArrayList<FileSystem> includeds = new ArrayList<>(); public Folder (String _name) { name = _name; } public void add(FileSystem fileSystem) { includeds.add(fileSystem); } @Override public int getSize() { int total = 0; for (FileSystem included : includeds) { total += included.getSize(); } System.out.println(name + "폴더 크기 : " + total); System.out.println("- - - - -"); return total; } @Override public void remove() { for (FileSystem included : includeds) { included.remove(); } System.out.println(name + " 폴더 삭제"); System.out.println("- - - - -"); } }

CompositePattern.java

public class CompositePattern { public static void main(String[] args) { Folder schoolFolder = new Folder("학교"); Folder grade1Folder = new Folder("1학년"); Folder grade2Folder = new Folder("2학년"); schoolFolder.add(grade1Folder); schoolFolder.add(grade2Folder); File enterPhoto = new File("입학사진", 256); grade1Folder.add(enterPhoto); Folder sem1Folder = new Folder("1학기"); Folder sem2Folder = new Folder("2학기"); grade2Folder.add(sem1Folder); grade2Folder.add(sem2Folder); File lecturePlan = new File("강의계획서", 120); sem1Folder.add(lecturePlan); Folder projFolder = new Folder("프로젝트"); sem2Folder.add(projFolder); File draft = new File("드래프트", 488); File finalResult = new File("결과물", 560); projFolder.add(draft); projFolder.add(finalResult); schoolFolder.getSize(); // 입학사진파일 크기 : 256 // 1학년폴더 크기 : 256 // - - - - - // 강의계획서파일 크기 : 120 // 1학기폴더 크기 : 120 // - - - - - // 드래프트파일 크기 : 488 // 결과물파일 크기 : 560 // 프로젝트폴더 크기 : 1048 // - - - - - // 2학기폴더 크기 : 1048 // - - - - - // 2학년폴더 크기 : 1168 // - - - - - // 학교폴더 크기 : 1424 // - - - - - schoolFolder.remove(); // 입학사진 파일 삭제 // 1학년 폴더 삭제 // - - - - - // 강의계획서 파일 삭제 // 1학기 폴더 삭제 // - - - - - // 드래프트 파일 삭제 // 결과물 파일 삭제 // 프로젝트 폴더 삭제 // - - - - - // 2학기 폴더 삭제 // - - - - - // 2학년 폴더 삭제 // - - - - - // 학교 폴더 삭제 // - - - - - } }

🍿 더 자세한 내용은 영상에서 보실 수 있습니다.





관련 태그의 다른 영상들

객체지향 디자인 패턴 2
Facade, Template-method, Decorator, Factory, Abstract-factory Mediator, Composite 패턴들을 알아봅니다.
# 객체지향
# 디자인패턴
# 상속
# interface
# 객체
# super
객체지향 디자인 패턴 1
Singleton, Strategy, State, Command, Adapter, Proxy 패턴들을 알아봅니다.
# 객체지향
# 디자인패턴
# singleton
# 상속
# interface
# 객체
객체지향 프로그래밍이 뭔가요?
붕어빵으로만 배워온 객체지향. 속 시원하게 알려드립니다.
# 객체지향
# 상속
# interface
# 객체
...