가람님 강의를 보고 작성한 문서입니다.
**생성패턴**
설계를 할 때 자주 발생하는 문제들을 피하기 위해 사용되는 패턴.
보통 생성자를 생성하는 문제와 관련된다.
패턴사용이유예시설명
추상팩토리 (Abstract Factory) | 연관된 서브 클래스를 특정 그룹으로 묶어 한번에 교체할 수 있게 하기위해 사용 | 인터페이스를 구현한 메서드에서 같은 메서드명으로 각각 다른 객체를 반환한다. | |
팩토리 (Factory Method) | 객체를 만들어 반환하는 함수를 (생성자 대신) 제공하여 초기화 과정을 외부에서 보지 못하게 숨기고 반환 타입을 제어하는 방법.<br />팩토리 기능을 하는 함수가 자기자신에 포함: 생성객체의 수를 조절하거나, 생성순서를 조정하거나, 생성직후 반환값을 사용해서 계산하는게 주 업무인 객체. 객체의 구체적인 타입을 숨기거나 도중에 바꾸고 싶은경우 등. | ||
빌더 (Builder) | 생성자의 파라미터가 많은경우 쉽게 인스턴스를 생성하기위해 사용 | 파라미터가 많은경우 체인을 이용해 객체생성 | |
프토토타입 (Prototype) | 인스턴스를 생성하기가 복잡하고 까다로울 때 사용 | 원본(Prototype)을 만들어 놓고 원본 객체를 복사하여 사용하는 방식. | |
싱글톤 (Singleton) | 인스턴스를 하나만 생성하고자 할 때 사용 | 테니스점수판 | 하나의 인스턴스만 생성 |
1. Abstract Factory Pattern
date: 07.01
![image-20210701171616378](../../assets/images/image-20210701171616378.png)
생성부분의 가상화/관련있는 객체
인스턴스를 생성하는 메서드를 하나만 사용
System.out.println(System.getProperty("os.name")); // Windows 10
// System.getProperty("os.name") 운영체제 반환함수
**사용방법**
- 팩토리 인터페이스 생성
public interface GuiFac {
public Button createButton();
public TextArea createTextArea();
}
- 인터페이스를 구현하는 객체생성 메서드 구현
class MacGutFac implements GuiFac {
@Override
public Button createButton() {
return new MacButton();
}
@Override
public TextArea createTextArea() {
return new MacTextArea();
}
}
- 객체 인터페이스와 구현된 클래스 생성
class MacButton implements Button {
@Override
public void click() {
System.out.println("맥 버튼 ");
}
}
class MacTextArea implements TextArea {
@Override
public String getText() {
return "맥 텍스트 에어리어";
}
}
- 똑같은 메서드로 여러 객체를 생성함을 볼 수 있다.
public class Main {
public static void main(String[] args) {
BikeFactory factory = new GtBikeFactory();
Body body = factory.createBody();
Wheel wheel = factory.creatWheel();
System.out.println(body.getClass());
System.out.println(wheel.getClass());
}
}
Q. 팩토리메서드 패턴과 추상팩토리 패턴의 차이점은?
A. 팩토리메서드 패턴은 하나의 메서드가 여러 객체를 생성하지만 추상팩토리 패턴은 여러 객체가 여러종류의 객체를 생성합니다.
2. Factory Method Pattern
![image-20210622222915299](../../assets/images/image-20210622222915299.png)
팩토리 메서드 : 템플릿 메소드 패턴이 사용된다.
**Application**
public class Application {
public static void main(String[] args) {
Creator creator = new DefaultItemCreator();
Item item1 = creator.create("나무칼");
Item item2 = creator.create("나무방패");
Item item3 = creator.create("나무갑주");
item1.use();
item2.use();
item3.use();
}
}
**Item class**
public abstract class Item {
public abstract void use();
}
**DefaultItem 자식 클래스**
public class DefaultItem extends Item {
private String itemName;
public DefaultItem(String itemName) {
this.itemName = itemName;
}
@Override
public void use() {
System.out.println(itemName +" 사용했습니다!");
}
}
**Creator class**
public abstract class Creator {
// 여러 메소드들을 추상화하여 자식에서 선언하고
abstract protected String init(String itemName);
abstract protected Item createItem(String itemName);
abstract protected String end(String itemName);
// 하나의 메서드에서 추상화한 메서드를 구현하면 팩토리메서드 패턴의 완성!!
public Item create(String itemName) {
init(itemName);
Item item = createItem(itemName);
end(itemName);
return item;
}
}
**Creator 자식 클래스**
package com.parkgaram.dp.templatecreator;
import com.parkgaram.dp.templatecreator.fw.Creator;
import com.parkgaram.dp.templatecreator.fw.Item;
public class DefaultItemCreator extends Creator {
@Override
protected String end(String itemName) {
System.out.println("Default 마무리 작업!");
return itemName;
}
@Override
protected String init(String itemName) {
System.out.println("Default 초기 작업!");
return itemName;
}
@Override
protected Item createItem(String itemName) {
return new DefaultItem(itemName);
}
}
##
3. Builder pattern
![image-20210622225438940](../../assets/images/image-20210622225438940.png)
빌더패턴은 두 가지로 나뉘는 것 같다.
- GOF 의 : 복잡한 단계를 거쳐야 생성되는 객체의 구현을 서브클래스에게 넘겨주는 패턴
- Effective Java 의 : 많은 인자를 가진 객체의 생성을 다른 객체의 도움으로 생성하는 패턴
GOF Builder
객체의 생성과 표현을 분리하여 다양한 조합을 가질 수 있게 도와준다.
GOF빌더패턴에는 크게 Builder, Concrete Builder, Director, Product 가 있다.
Builder : 추상 클래스
Concrete Builder : Builder 를 상속받아 기능을 정의하는 실질적인 객체
Director : Builder 의 함수를 사용하여 Product 를 만드는 클래스
Product
Effective Java
![Effective Java Joshua Bloch 안녕 Addison-Wesley Professional](../../assets/images/x9780134685991.jpg)
static inner class 를 만들어서 사용한다.
점층적 생성자패턴과 자바빈즈 패턴의 장점을 섞은 것이 Effective Java 의 빌더패턴입니다.
- 점층적생성자 패턴 예시
Computer gram = new Computer("LG", "i7", "8GB", "256GB", "SSD");
단점
- 인자들이 많아 질 수록 생성자의 숫자 역시 많아진다 : 필수입력과 선택입력이 있기때문에
- 같은 자료형은 실수로 바꿔 넣는 실수가 생길 수 있다.
- 가독성이 떨어진다 : 매개변수이름이나 주석을 참고해야 한다.
- 자바빈즈 패턴 예시
PersonInfo personInfo = new PersonInfo( );
personInfo.setName("Mommoo");
personInfo.setAge(12);
personInfo.setPhonNumber(119);
단점
- 코드량이 늘어난다.
- 객체 일관성이 깨진다.
**Builder pattern 예시**
Computer gram = ComputerBuilder
.startWithBrand("LG")
.setCpu("i7")
.setRam("8GB")
.setCapacity("256GB") // 이것을 체인이라고 합니다.
.setDiskDrive("SSD")
.build();
두 패턴의 단점을 개선했다.
4. Prototype pattern
date: 06.22
![image-20210622222625544](../../assets/images/image-20210622222625544.png)
생산비용이 높은 인스턴스를 복사를 통해서 쉽게 생성 할 수 있도록 하는 패턴
생산비용이 높은경우
- 종류가 너무 많아서 클래스로 정리되지 않는 경우
- 클래스로부터 인스턴스 생성이 어려운 경우
**작성방법**
- `implements Cloneable` 이미 정의된 Object 의 인터페이스를 사용
- `(캐스팅) clone()` 깊은복사를 유의하며 복사메서드를 이용해 재정의하여 사용
`Object clone()`
**얕은복사와 깊은복사**
얕은복사 : 참조형변수에서 같은 주소를 가리키는 것 : 등호 (=) 를 참조형변수에 사용
깊은복사 : 참조형변수에서 주소가 아닌 값만 복사하는 것
**예시**
**Main**
public class Application {
public static void main(String[] args) throws CloneNotSupportedException {
Circle circle1 = new Circle();
circle1.setId("1");
circle1.setX(1);
circle1.setY(1);
circle1.setR(3);
circle1.a.x = 1;
Circle circle2 = (Circle) circle1.copy();
System.out.println(circle1.a.x);
System.out.println(circle2.a.x);
circle1.a.x = 2;
System.out.println(circle1.a.x);
System.out.println(circle2.a.x);
circle2.a.x = 3;
System.out.println(circle1.a.x);
System.out.println(circle2.a.x);
}
}
**Shape**
public abstract class Shape implements Cloneable {
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
**Prototype class**
public class Circle extends Shape {
int x, y;
int r;
public Double d;
public A a;
public Circle() {
a = new A();
}
public void setA(A a) {
this.a = a;
}
public A getA() {
return a;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getR() {
return r;
}
public void setR(int r) {
this.r = r;
}
public Shape copy() throws CloneNotSupportedException {
Circle shape = (Circle) clone();
shape.x += 1;
shape.y += 1;
shape.setA((A)shape.getA().clone());
return shape;
}
}
##
5. Singleton Pattern
![image-20210622222849543](../../assets/images/image-20210622222849543.png)
싱글톤 패턴 : 하나의 인스턴스만 생성해야 할 객체를 위한 패턴
구현방법에는 사전 초기화 (Eager Initialization) 과 사후 초기화 (Lazy Initialization) 이 있다.
사전 초기화: 클래스 로딩시에 인스턴스를 생성. 멀티스레드 환경에서의 이중객체 생성문제에 안전하다.
예시
class Singleton {
static final Singleton instance = new Singleton();
private Singleton() {
//초기화
}
public Singleton getInstance() {
return instance;
}
}
사후 초기화: 인스턴스를 사용할 시점에서 인스턴스를 생성. 메모리효율과 연산효율이 좋다.
사후 초기화의 예시는 아래에 있다.
**작성방법**
- `private static 클래스 instance`
- `private 생성자` 메인클래스에서 생성할 수 없게 함
- `public static 클래스 getInstance` 메서드의 반환으로 인스턴스 호출
**Application**
public class Application {
public static void main(String[] args) {
SystemSpeaker LG = SystemSpeaker.getInstance();
SystemSpeaker SAMSUNG = SystemSpeaker.getInstance();
System.out.println(LG.getVolume());
System.out.println(SAMSUNG.getVolume());
LG.setVolume(10);
System.out.println(LG.getVolume());
System.out.println(SAMSUNG.getVolume());
SAMSUNG.setVolume(20);
System.out.println(LG.getVolume());
System.out.println(SAMSUNG.getVolume());
}
}
**SystemSpeaker**
public class SystemSpeaker {
private static SystemSpeaker instance;
private int volume;
private SystemSpeaker() {
setVolume(5);
}
public static SystemSpeaker getInstance() {
if (instance == null) {
instance = new SystemSpeaker();
}
return instance;
}
public int getVolume() {
return volume;
}
public void setVolume(int volume) {
this.volume = volume;
}
}
**구조패턴**
패턴사용이유예시설명
어댑터 | 이미 만들어진 클래스를 변경하고싶지 않거나 불가능한 경우에 사용 | ||
브리지 | 기능과 구현이 중복되어 다양한 경우 | 기능과 구현을 분리하여 연결한다. | |
컴포지트 | 폴더 파일 관계처럼 트리구조화 한다. | ||
데코레이터 | |||
파사드 (Facade) | 프랑스어로 건물의 정면 외벽을 가리킨다. |
1. Adapter Pattern
![image-20211016214102961](../../../assets/images/image-20211016214102961.png)
어댑터 패턴
기계, 기구 등을 사전적 의미 : 다목적으로 사용하기 위한 부가 기구
오리 (Duck) 클래스가 먼저 있고 후에 칠면조 (Turkey) 클래스가 추가되었다.
**오리**
public interface Duck {
public void quack();
public void fly();
}
public class MallardDuck implements Duck {
@Override
public void quack() {
System.out.println("Quack");
}
@Override
public void fly() {
System.out.println("I'm flying");
}
}
**칠면조**
public interface Turkey {
public void gobble();
public void fly();
}
public class WildTurkey implements Turkey{
@Override
public void gobble() {
System.out.println("Gobble gobble");
}
@Override
public void fly() {
System.out.println("I'm flying a short distance");
}
}
**Main**
public class DuckTestDrive {
public static void main(String[] args) {
MallardDuck duck = new MallardDuck();
WildTurkey turkey = new WildTurkey();
System.out.println("The turkey says...");
turkey.gobble();
turkey.fly();
System.out.println("The Duck says...");
testDuck(duck);
}
public static void testDuck(Duck duck){
duck.quack();
duck.fly();
}
}
Duck 과 Turkey 의 인터페이스가 달라 testDuck 에 Turkey 를 넣을 수가 없게 되었다.
이때 메인과 Duck, Turkey 어떠한 것도 바꾸지 않고 어댑터클래스를 추가하여 해결할 수 있다.
Duck turkeyAdapter = new TurkeyAdapter(turkey);
System.out.println("The TurkeyAdapter says...");
testDuck(turkeyAdapter);
이때 클라이언트에서는 호출 결과를 받긴 하지만 중간에 어댑터가 끼워져 있는지는 전혀 알지 못한다.
![image-20210622222959828](../../assets/images/image-20210622222959828.png)
`Float.doubleValue()` double 로 변환
main 메서드를 변경하지 않고 AdapterImpl class 에서 Math.doubled 를 바꿈으로써 간단히 변경
**3개의 구성**
- static Math
- Adaper interface
- AdapterImpliment
interface 에 Array 를 List 변환 후 sort 후 Array 재 변환의 기능을 넣어도 된다.
**예시**
public class Application {
public static void main(String[] args) {
//요구사항을 수행하는 인스턴스
Adapter target = new AdapterImpl();
System.out.println(target.twiceOf(100.0f));
System.out.println(target.halfOf(100.3f));
}
}
public interface Adapter {
public Double twiceOf(Float num);
public Double halfOf(Float num);
}
public class AdapterImpl implements Adapter {
@Override
public Double twiceOf(Float num) {
return Math.doubled(num.doubleValue());
}
@Override
public Double halfOf(Float num) {
return Math.half(num);
}
}
2. Bridge Pattern
구현과 기능을 분리한다는 것이 핵심이다.
동물과 사냥방식으로 나눠보자.
**사냥방식 인터페이스**
public interface Hunting_Handler {
public void Find_Quarry();
public void Detected_Quarry();
public void attack();
}
**공중 사냥방식**
public class Hunting_Method1 implements Hunting_Handler {
public void Find_Quarry()
{
System.out.println("물 위에서 찾는다");
}
public void Detected_Quarry()
{
System.out.println("물고기 발견!");
}
public void attack()
{
System.out.println("낚아챈다.");
}
}
**지상 사냥방식**
public class Hunting_Method2 implements Hunting_Handler {
public void Find_Quarry()
{
System.out.println("지상에서 찾는다");
}
public void Detected_Quarry()
{
System.out.println("노루 발견");
}
public void attack()
{
System.out.println("물어뜯는다.");
}
}
**동물 클래스**
public class Animal {
private Hunting_Handler hunting;
public Animal(Hunting_Handler hunting)
{
this.hunting=hunting;
}
public void Find_Quarry()
{
hunting.Find_Quarry();
}
public void Detected_Quarry()
{
hunting.Detected_Quarry();
}
public void attack()
{
hunting.attack();
}
public void hunt()
{
Find_Quarry();
Detected_Quarry();
attack();
}
}
**타이거**
public class Tiger extends Animal
{
public Tiger(Hunting_Handler hunting)
{
super(hunting);
}
public void hunt()
{
System.out.println("호랑이의 사냥방식");
Find_Quarry();
Detected_Quarry();
attack();
}
}
**새**
public class Bird extends Animal
{
public Bird(Hunting_Handler hunting)
{
super(hunting);
}
public void hunt()
{
System.out.println("새의 사냥방식");
Find_Quarry();
Detected_Quarry();
attack();
}
}
**Main**
public class Main {
public static void main(String argsp[])
{
Animal tiger = new Tiger(new Hunting_Method2());
Animal bird = new Bird(new Hunting_Method1());
tiger.hunt();
System.out.println("--------------");
bird.hunt();
}
}
![image-20211016220525711](../../../assets/images/image-20211016220525711.png)
![image-20210701185049285](../../assets/images/image-20210701185049285.png)
function 메서드로 implementation 메서드를 실행한다.
재정의된 function 메서드가 오버라이딩된 구체적인 implementation 메서드를 실행하는 그림이 된다.
**모스부호 예제**
**출력**
반짝 반짝 번쩍 - 번쩍 반짝 - 번쩍 반짝 번쩍 - 번쩍 반짝 - 반짝 반짝 -
삐~삐~삣 삣삐~ 삣삐~삣 삣삐~ 삐~삐~
--· ·- ·-· ·- --
**Main**
public class Ch09main {
public static void main(String[] args) {
PrintMorseCode code = new PrintMorseCode(new FlashMCF());
code.g().a().r().a().m();
System.out.println();
code.setFunction(new SoundMCF());
code.g().a().r().a().m();
System.out.println();
code.setFunction(new DefaultMCF());
code.g().a().r().a().m();
}
}
**Abstraction**
public class MorseCode {
private MorseCodeFunction function;
public MorseCode(MorseCodeFunction function) {
this.function = function;
}
public void setFunction(MorseCodeFunction function) {
this.function = function;
}
public void dot() {
function.dot();
}
public void dash() {
function.dash();
}
public void space() {
function.space();
}
}
**RefinedAbstraction**
public class PrintMorseCode extends MorseCode {
public PrintMorseCode(MorseCodeFunction function) {
super(function);
}
public PrintMorseCode g() {
dash();
dash();
dot();
space();
return this;
}
public PrintMorseCode a() {
dot();
dash();
space();
return this;
}
public PrintMorseCode r() {
dot();
dash();
dot();
space();
return this;
}
public PrintMorseCode m() {
dash();
dash();
space();
return this;
}
}
**Implementation**
public interface MorseCodeFunction {
public void dot();
public void dash();
public void space();
}
**ConcreteImplementation**
public class DefaultMCF implements MorseCodeFunction{
@Override
public void dot() {
System.out.print("·");
}
@Override
public void dash() {
System.out.print("-");
}
@Override
public void space() {
System.out.print(" ");
}
}
public class SoundMCF implements MorseCodeFunction{
@Override
public void dot() {
System.out.print("삣");
}
@Override
public void dash() {
System.out.print("삐~");
}
@Override
public void space() {
System.out.print(" ");
}
}
public class FlashMCF implements MorseCodeFunction {
@Override
public void dot() {
System.out.print(" 번쩍 ");
}
@Override
public void dash() {
System.out.print(" 반짝 ");
}
@Override
public void space() {
System.out.print(" - ");
}
}
3. Composite Pattern
date: 07.04
트리구조를 구현하자
![image-20210704181234448](../../assets/images/image-20210704181234448.png)
**인터페이스 혹은 추상클래스로 Component 생성**
abstract public class Component {
private String name;
public Component(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
**Component 의 자식 파일클래스**
public class File extends Component {
private Object data;
public File(String name) {
super(name);
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
**Component 의 자식 폴더클래스**
import java.util.ArrayList;
import java.util.List;
public class Folder extends Component {
List<Component> children = new ArrayList<>();
public Folder(String name) {
super(name);
}
public boolean addComponent(Component component) {
return children.add(component);
}
public boolean removeComponet(Component component) {
return children.remove(component);
}
public List<Component> getChildren() {
return children;
}
}
**Main**
public class C10composite {
public static void main(String[] args) {
Folder
root = new Folder("root"),
home= new Folder("home"),
garam= new Folder("garam"),
music= new Folder("music"),
picture= new Folder("picture"),
doc= new Folder("doc"),
usr= new Folder("usr");
File
track1 = new File("track1"),
track2 = new File("track2"),
pic1 = new File("pic1"),
doc1 = new File("doc1"),
java = new File("java");
root.addComponent(home);
home.addComponent(garam);
garam.addComponent(music);
music.addComponent(track1);
music.addComponent(track2);
garam.addComponent(picture);
picture.addComponent(pic1);
garam.addComponent(doc);
doc.addComponent(doc1);
root.addComponent(usr);
usr.addComponent(java);
show(root);
}
private static void show(Component component){
System.out.println(component.getClass().getName()+"|"+component.getName());
if(component instanceof Folder){
for (Component c : ((Folder)component).getChildren()) {
show(c);
}
}
}
}
4. Decorator Pattern
동적으로 책임추가가 필요할 때 사용
![image-20210704185017664](../../assets/images/image-20210704185017664.png)
Decorator 는 Component 이며 Component 를 가진다.
public interface IBeverage {
int getTotalPrice();
}
public class Base implements IBeverage {
@Override
public int getTotalPrice() {
return 0;
}
}
abstract public class AbstAdding implements IBeverage {
private IBeverage base;
public AbstAdding(IBeverage base) {
this.base = base;
}
@Override
public int getTotalPrice() {
return base.getTotalPrice();
}
protected IBeverage getBase() {
return base;
}
}
public class Espresso extends AbstAdding {
static protected int espressoCount = 0;
public Espresso(IBeverage base) {
super(base);
}
@Override
public int getTotalPrice() {
return super.getTotalPrice() + getAddPrice();
}
private static int getAddPrice() {
espressoCount += 1;
int addPrice = 100;
if (espressoCount > 1) {
addPrice = 70;
}
return addPrice;
}
}
public class Milk extends AbstAdding {
public Milk(IBeverage meterial) {
super(meterial);
}
@Override
public int getTotalPrice() {
return super.getTotalPrice()+50;
}
}
**Main**
import java.util.Scanner;
import com.parkgaram.dp.chapter11.abst.IBeverage;
import com.parkgaram.dp.chapter11.concrete.Base;
import com.parkgaram.dp.chapter11.concrete.Espresso;
import com.parkgaram.dp.chapter11.concrete.Milk;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// base
IBeverage beverage = new Base();
boolean done = false;
while (!done) {
System.out.println("음료 현재 가격 : " + beverage.getTotalPrice());
System.out.print("선택 : 1:샷 추가 / 2:우유 추가");
switch (sc.nextInt()) {
case 0:
done = true;
break;
case 1:
beverage = new Espresso(beverage);
break;
case 2:
beverage = new Milk(beverage);
break;
}
}
System.out.println("음료 가격 : " + beverage.getTotalPrice());
sc.close();
}
}
**행위패턴**
- 책임체인
- 커맨드
- 인터프리터
- 반복자
- 중재자
- 메멘토
- 옵저버
- 상태
- 전략: 추상팩토리와 비슷하다.
- 템플릿 메서드: 일부만 바뀔 때
- 방문자
9. Strategy Pattern
![image-20210622223024990](/assets/images/image-20210622223024990.png)
인터페이스
델리게이트 : 떠넘기는 것
Strategy Pattern : 여러 알고리즘을 하나의 추상적인 접근점 (인터페이스) 를 만들어 접근 점에서 서로 교환 가능하도록 하는 패턴.
- interface 사용 예제
public class Main {
public static void main(String[] args) {
Ainterface ainterface = new AinterfaceImpl();
// 가능
AinterfaceImpl ainterface = new AinterfaceImpl();
// 불가능
AinterfaceImpl ainterface = new Ainterface();
Ainterface ainterface = new Ainterface();
}
}
- Main
public class Main {
public static void main(String[] args) {
GameCharacter bobi = new GameCharacter();
bobi.setWeapon(new Knife());
bobi.attact();
}
}
- Character
public class GameCharacter {
private Weapon weapon;
public void attact() {
if (weapon == null) {
System.out.println("맨손 공격");
} else {
weapon.doAttact();
}
}
public void setWeapon(Weapon weapon) {
this.weapon = weapon;
}
}
- Weapon interface
public interface Weapon {
public void doAttact();
}
- Weapon 의 클래스 : Sword
public class Sword implements Weapon {
public void doAttact() {
System.out.println("검 공격");
}
}
- Weapon 의 클래스 : Knife
public class Knife implements Weapon {
public void doAttact() {
System.out.println("칼 공격");
}
}
- 로봇예시
public class Client {
public static void main(String[] args) {
Robot taekwonV = new TaekwonV("TaekwonV");
Robot atom = new Atom("Atom");
/* 수정된 부분: 전략 변경 방법 */
taekwonV.setMovingStrategy(new WalkingStrategy());
taekwonV.setAttackStrategy(new MissileStrategy());
atom.setMovingStrategy(new FlyingStrategy());
atom.setAttackStrategy(new PunchStrategy());
/* 아래부터는 동일 */
System.out.println("My name is " + taekwonV.getName());
taekwonV.move();
taekwonV.attack();
System.out.println()
System.out.println("My name is " + atom.getName());
atom.move();
atom.attack();
}
}
10. Template Method Pattern
![image-20210622222939263](../../assets/images/image-20210622222939263.png)
템플릿 메서드 패턴
사전적 의미 : 모양자
언제 사용하는가?
- 알고리즘이 일정한 프로세스가 있다. (여러 단계로 나눌 수 있다.)
- 알고리즘이 변경가능성이 클 때
- 알고리즘을 여러단계로 나눈다.
- 단계를 메소드로 선언한다.
- 템플릿 메소드를 만든다.
- 하위클래스에서 나눠진 메소드를 구현한다.
추상클래스에 메서드 1, 2, 3 선언
유저 접속 시
- 보안
- 인증
- 권한
- 접속
abstract 클래스에는 abstract 변수 선언
abstract 를 protected 와 같이 쓴다 : 자식에서 선언해야 되기 때문
`throw new Error("셧다운")` 에러문자 남기기
추상클래스에 추상메서드들 (자식에서 구현) 과 하나의 public 클래스
**추상클래스**
public abstract class AbstConnectHelper {
abstract protected String doSecurity(String info);
abstract protected String authentication(String id, String password);
abstract protected int authorization(String userName);
abstract protected String connection(String info);
public String requestConnection(String info) {
String id, password, userName, decodedInfo, userInfo;
// 암호화된 정보를 복호화 합니다.
// doSecurity 는 getInfo 즉 getter 함수
decodedInfo = doSecurity(info);
// decodedInfo에서 id 와 password를 추출
id = "abc";
password = "abc";
userInfo = authentication(id, password);
// userInfo에서 userName을 찾아 냅니다.
userName = "abc";
int result = authorization(userName);
switch (result) {
case 0:// 무료회원
break;
case 1:// 유료회원
break;
case 2:// 게임 마스터
break;
case 3:// 접속 권한 없음
break;
default:
break;
}
return connection(userInfo);
}
}
**자식클래스**
public class ConcreteConnectHelper extends AbstConnectHelper {
@Override
protected String doSecurity(String info) {
return info;
}
@Override
protected String authentication(String id, String password) {
if(id.equals("abc")|password.equals("abc"))
return "true info";
else
return "false info";
}
@Override
protected int authorization(String userName) {
return 0;
}
@Override
protected String connection(String info) {
return info;
}
}