본문 바로가기
Java/POJO

디자인 패턴

by java개발자 2017. 9. 22.

youtube의 디자인 패턴 강의를 보면서 정리함. 소스위주

https://www.youtube.com/watch?v=UEjsbd3IZvA&index=1&list=PLsoscMhnRc7pPsRHmgN4M8tqUdWZzkpxY

소스 출처

https://bitbucket.org/garampark/java-design-pattern/src/ed39c43449f60428450e8c647d05f77f2f642ef1/Chapter08-AbstractFactory-2/src/Main.java?at=master&fileviewer=file-view-default


소스는 일부 수정함

각 챕터별로 한눈에 보기 위해 1개의 class 파일에 다 넣음.


1장

/**
 * 디자인 패턴을 사용하는 이유는 협업을 위해서
 * 내 의도의 틀 안에서 상대방이 다음 코드를 원활하게 작성할 수 있도록 하기 위해
 * 오픈소스 라이브러리 배포 jar 환경이기 때문에 가능한듯  
 */
/**
 * 01. strategy : 전략 바꾸기
 */
interface Weapon {
	void attack();
}
class Knife implements Weapon {
	@Override
	public void attack() {
		System.out.println("Knife");
	}
}
class Sword implements Weapon {
	@Override
	public void attack() {
		System.out.println("Sword");
	}
}
class Character {
	private Weapon w;

	public Character(Weapon w) {
		this.w = w;
	}
	public void attack() {
		w.attack();	// 위임
	}
}
public class _01_Main {
	public static void main(String[] args) {
		Character character1 = new Character(new Knife());	// 전략1
		character1.attack();
		Character character2 = new Character(new Sword());	// 전략2
		character2.attack();
	}
}


2장

/**
 * 02. adapter : 연관성 없는 두 객체 묶어 사용하기 
 * 기존 라이브러리를 바로 실행하지 않고, 한번 거쳐서 사용하기
 */
class ExistLibrary {
	public static double twoTime(double num) {
		return num * 2;
	}
	public static double half(double num) {
		return num / 2;
	}
}
interface Adapter {
	float twoTime(float f);
	float half(float f);
}
class AdapterImpl implements Adapter {
	@Override
	public float twoTime(float f) {
		System.out.println("로그 찍기");
		return (float) ExistLibrary.twoTime(f);
	}
	@Override
	public float half(float f) {
		return (float) ExistLibrary.half(f);
	}
}
public class _02_Main {
	public static void main(String[] args) {
		AdapterImpl adapterImpl = new AdapterImpl();
		float result1 = adapterImpl.twoTime(12.2f);
		float result2 = adapterImpl.twoTime(1.2f);
		System.out.println(result1);
		System.out.println(result2);

	}
}



3장

/**
 * 03. template : 공통적인 프로세스를 묶어주기 
 * 모양자 
 * 알고리즘의 구조(순서)를 메소드에 정의하고 
 * 하위 클래스에서 알고리즘 구조의 변경없이
 * 알고리즘을 재정의 하는 패턴
 */

abstract class Helper {
	// 같은 패키지에서만 보이도록
	protected abstract String doA(String s);
	protected abstract boolean doB(String s);
	protected abstract int doC(String s);
	protected abstract String doD(String s);
	protected abstract String doE(String s);

	// 알고리즘 구조
	public String request(String s) {
		// step1
		String a = doA(s);
		// step2
		if (doB(a)) {
			throw new Error("EEEE");
		}
		// step3
		int i = doC(s);
		if (i > 0) {
			// step4
			doD(s);
		}
		// step5
		return doE(s);
	}
}
class ImplHelper extends Helper {
	@Override
	protected String doA(String s) {
		// TODO 구현 필요
		return null;
	}
	@Override
	protected boolean doB(String s) {
		// TODO
		return false;
	}
	@Override
	protected int doC(String s) {
		// TODO
		return 0;
	}
	@Override
	protected String doD(String s) {
		// TODO
		return null;
	}
	@Override
	protected String doE(String s) {
		// TODO
		return null;
	}
}
public class _03_Main {
	public static void main(String[] args) {
		ImplHelper h = new ImplHelper();
		h.request("ID");
	}
}

4장

/**
 * 04. factory : 생성의 템플릿 메소드 패턴(템플릿을 이용해서 팩토리 구현)
 */
interface Item {
	void use();
}
class HpPotion implements Item {
	@Override
	public void use() {
		System.out.println("HP회복");
	}
}
class MpPotion implements Item {
	@Override
	public void use() {
		System.out.println("MP회복");
	}
}
abstract class ItemCreator {
	public Item create() {
		// step1
		requestItemInfo();
		// step2
		Item item = createItem();
		return item;
	}
	abstract protected void requestItemInfo();
	abstract protected Item createItem();
}
class HpCreator extends ItemCreator {
	@Override
	protected void requestItemInfo() {
		// TODO Auto-generated method stub
	}
	@Override
	protected Item createItem() {
		// TODO Auto-generated method stub
		return new HpPotion();
	}
}
class MpCreator extends ItemCreator {
	@Override
	protected void requestItemInfo() {
		// TODO Auto-generated method stub
	}
	@Override
	protected Item createItem() {
		// TODO Auto-generated method stub
		return new MpPotion();
	}
}
public class _04_Main {
	public static void main(String[] args) {
		ItemCreator creator = new HpCreator();
		Item item1 = creator.create();
		item1.use();
		
		ItemCreator creator2 = new MpCreator();
		Item item2 = creator2.create();
		item2.use();
	}
}



5장

/**
 * 05. singleton : 하나의 인스턴스만 있도록 하기
 */
class Speaker {
	static private Speaker instance;
	public Speaker() {

	}
	public static Speaker getInstance() {
		if (instance == null) {
			instance = new Speaker();
			System.out.println("새로생성");
		}else {
			System.out.println("이미생성");
		}
		return instance;
	}
}
public class _05_Main {
	public static void main(String[] args) {
		Speaker instance1 = Speaker.getInstance();
		Speaker instance2 = Speaker.getInstance();
		
		System.out.println(instance1.hashCode());
		System.out.println(instance2.hashCode());
	}
}


6장

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

/**
 * 06. 프로토타입 : 생산 비용 줄이기 (복잡한 인스턴스 복사하기)
 */
@Setter @Getter @ToString
class Path implements Cloneable {	// deep copy를 위해서 준비
	private int i;
	public Path(int i) {
		this.i = i;
	}
	// super.clone이 protected이므로, Path에 public clone 함수로 감싸줘야 한다. Adapter느낌
	public Path clone() throws CloneNotSupportedException {
		return (Path) super.clone();
	}
}
@Setter @Getter @ToString
class Shape implements Cloneable {
	private String id;
}
@Setter @Getter @ToString
class Circle extends Shape {
	private int x, y, r;
	private Path path;

	public Circle(int x, int y, int r, Path path) {
		super();
		this.x = x;
		this.y = y;
		this.r = r;
		this.path = path;
	}
	public void setPathI(int i) {
		this.path.setI(i);
	}
	public Circle copy() throws CloneNotSupportedException {
		Circle circle = (Circle) super.clone();	// 숫자, 문자만? 얕은복사만
		circle.setPath(this.path.clone());
		circle.x += 1;
		circle.y += 1;
		return circle;
	}
}
public class _06_Main {
	public static void main(String[] args) throws CloneNotSupportedException {
		Circle circle1 = new Circle(1,2,3,new Path(4));
		Circle circle2 = circle1.copy();
		
		circle1.setX(3);
		circle1.setPathI(2);
		System.out.println(circle1.getX() + ", " + circle1.getPath());
		System.out.println(circle2.getX() + ", " + circle2.getPath());
	}
}

7장-1

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

/**
 * 07. 빌더 : 복잡한 단계가 필요한 인스턴스 생성을 빌더패턴을 통해서 구현할 수 있다. (템플릿과 비슷)
 * 복잡한 단계를 거쳐야 생성되는 객체의 구현을 서브클래스에게 넘겨주는 패턴
 */
@Setter @Getter @ToString
class Computer {
	private String cpu;
	private String ram;
	private String storage;
	
	public Computer(String cpu, String ram, String storage) {
		super();
		this.cpu = cpu;
		this.ram = ram;
		this.storage = storage;
	}
}
abstract class BluePrint {
	abstract public void setCpu();
	abstract public void setRam();
	abstract public void setStorage();
	abstract public Computer getComputer();
}
class LgGramBlueprint extends BluePrint{
	private Computer computer;
	public LgGramBlueprint() {
		computer = new Computer("default", "default", "default");
	}
	@Override
	public void setCpu() {
		computer.setCpu("i7");
	}

	@Override
	public void setRam() {
		computer.setRam("8g");
	}

	@Override
	public void setStorage() {
		computer.setStorage("256g ssd");
	}
	@Override
	public Computer getComputer() {
		return this.computer;
	}
}
//class HPBlueprint extends BluePrint{...
class Factory {
	private BluePrint print;
	public void setBlueprint(BluePrint print) {
		this.print = print;
	}
	public void make() {
		print.setCpu();
		print.setRam();
		print.setStorage();
	}
	public Computer getComputer() {
		return print.getComputer();
	}
}
public class _07_1_Main {
	public static void main(String[] args) {
		Factory factory = new Factory();
		factory.setBlueprint(new LgGramBlueprint());
		factory.make();
		Computer computer = factory.getComputer();
		System.out.println(computer);
	}
}

7장-2

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

/**
 * 07. 빌더2 : 많은 인자를 가진 객체의 생성을
 * 다른 객체의 도움으로 생성하는 패턴
 */
@Setter @Getter @ToString
class Computer2 {
	private String cpu;
	private String ram;
	private String storage;
	
	public Computer2(String cpu, String ram, String storage) {
		super();
		this.cpu = cpu;
		this.ram = ram;
		this.storage = storage;
	}
}
class ComputerBuiler {
	private Computer2 computer;
	public ComputerBuiler() {
		computer = new Computer2("default", "default", "default");
	}
	public static ComputerBuiler startWithCpu(String cpu) {
		ComputerBuiler builder = new ComputerBuiler();
		builder.computer.setCpu(cpu);
		return builder;
	}
	public ComputerBuiler setRam(String ram) {
		computer.setRam(ram);
		return this;
	}
	public ComputerBuiler setStorage(String storage) {
		computer.setStorage(storage);
		return this;
	}
	public Computer2 build() {
		return computer;
	}
}
public class _07_2_Main {
	public static void main(String[] args) {
		Computer2 computer = ComputerBuiler.startWithCpu("i7")
				.setRam("8g")
				.setStorage("256g ssd")
				.build();
		System.out.println(computer);
	}
}

8장-1

/**
 * Abstract Factory : 객체 생성의 가상화
 */
interface Body {
}
interface Wheel {
}
class SamBody implements Body { 
}
class SamWheel implements Wheel { 
}
interface BikeFactory {
	Body createBody();
	Wheel createWheel();
}
class SamBikeFactory implements BikeFactory {
	@Override
	public Body createBody() {
		return new SamBody();
	}
	@Override
	public Wheel createWheel() {
		return new SamWheel();
	}
}
//class GTBikeFactory implements BikeFactory { ...
public class _08_1_Main {
	public static void main(String[] args) {
		BikeFactory factory = new SamBikeFactory();
		Body body = factory.createBody();
		Wheel wheel = factory.createWheel();
		System.out.println(body);
		System.out.println(wheel);
	}
}

8장-2

/**
 * Abstract Factory2
 */
interface Button {
	public void click();
}
interface TextArea {
	public String getText();
}
interface GuiFac {
	public Button createButton();
	public TextArea createTextArea();
}
class LinuxButton implements Button {
	@Override
	public void click() {
		System.out.println("리눅스 버튼 ");
	}
}
class LinuxTextArea implements TextArea {
	@Override
	public String getText() {
		return "리눅스 텍스트에어리어";
	}
}
class LinuxGuiFac implements GuiFac {
	@Override
	public Button createButton() {
		//
		return new LinuxButton();
	}
	@Override
	public TextArea createTextArea() {
		return new LinuxTextArea();
	}
}
//class MacButton implements Button {
//class MacTextArea implements TextArea {
//class MacGutFac implements GuiFac {
//class WinButton implements Button {
//class WinTextArea implements TextArea {
//class WinGutFac implements GuiFac {
class FactoryInstance {
	public static GuiFac getGuiFac() {
		switch (1) {	// TODO if
		case 0:
//			return new MacGutFac();
		case 1:
			return new LinuxGuiFac();
		case 2:
//			return new WinGutFac();
		}
		return null;
	}
}
public class _08_2_Main {
	public static void main(String[] args) {
		GuiFac fac = FactoryInstance.getGuiFac();

		Button button = fac.createButton();
		TextArea area = fac.createTextArea();

		button.click();
		System.out.println(area.getText());
		System.out.println(System.getProperty("os.name"));
	}
}

9장

/**
 * 09. 브릿지 - 기능 계층과 구현 계층의 분리
 */
interface MorseCodeFunction {
	public void dot();
	public void dash();
	public void space();
}
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(" - ");
	}
}
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(" ");
	}
}
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();
	}
}
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;
	}
}
public class _09_Main {
	public static void main(String[] args) {
		PrintMorseCode code = new PrintMorseCode(new FlashMCF());
		code.g().a().r().a().m();		
	}
}

10장

import java.util.ArrayList;
import java.util.List;

import lombok.Getter;
import lombok.Setter;

/**
 * 10. composite - tree 구조, 컨테이너와 내용물을 같게 다루기
 */
@Getter @Setter
abstract class Component {
	private String name;
	public Component(String name) {
		this.name = name;
	}
}
class Folder extends Component {
	List 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 getChildren() {
		return children;
	}
}
@Getter @Setter
class File extends Component {
	private Object data;
	public File(String name) {
		super(name);
	}
}
public class _10_Main {
	public static void main(String[] args) {
		Folder root = new Folder("root");
		Folder home = new Folder("home");
		Folder garam = new Folder("garam");
		Folder music = new Folder("music");
		Folder picture = new Folder("picture");
		Folder doc = new Folder("doc");
		Folder usr = new Folder("usr");

		File track1 = new File("track1");
		File track2 = new File("track2");
		File pic1 = new File("pic1");
		File doc1 = new File("doc1");
		File 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(String tab, Component component) {
		System.out.println(tab + component.getClass().getName() + "|" + component.getName());
		if (component instanceof Folder) {
			for (Component c : ((Folder) component).getChildren()) {
				show(tab + "  ", c);  // 재귀
			}
		}
	}
}

console결과: 

  Folder|root

    Folder|home

      Folder|garam

        Folder|music

          File|track1

          File|track2

        Folder|picture

          File|pic1

        Folder|doc

          File|doc1

    Folder|usr

      File|java


11장

import java.util.Scanner;

/**
 * 11. decorator : 동적으로 책임 추가
 */
interface IBeverage {
	int getTotalPrice();
}
class Base implements IBeverage {
	@Override
	public int getTotalPrice() {
		return 0;
	}
}
abstract class AbstAdding implements IBeverage {
	private IBeverage base;
	public AbstAdding(IBeverage base) {
		super();
		this.base = base;
	}
	protected IBeverage getBase() {
		return base;
	}
	@Override
	public int getTotalPrice() {
		return base.getTotalPrice();
	}
}
class Espresso extends AbstAdding {
	static protected int espressoCount = 0;
	public Espresso(IBeverage meterial) {
		super(meterial);
	}
	private static int getAddPrice(){
		espressoCount += 1;
		int addPrice = 100;
		if (espressoCount > 1) {
			addPrice = 70;
		}
		return addPrice;
	}
	@Override
	public int getTotalPrice() {
		return super.getTotalPrice() + getAddPrice();
	}
}
class Milk extends AbstAdding {
	public Milk(IBeverage meterial) {
		super(meterial);
	}
	@Override
	public int getTotalPrice() {
		return super.getTotalPrice() + 50;
	}
}
public class _11_Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		// base
		IBeverage beverage = new Base();	// 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);	// 지금까지의 beverage를 포함해서 다시 객체 생성
				break;
			case 2:
				beverage = new Milk(beverage);
				break;
			}
		}

		System.out.println("음료 가격 : " + beverage.getTotalPrice());
		sc.close();
	}
}

12장

import java.util.ArrayList;

import lombok.Getter;
import lombok.Setter;

/**
 * 12. visitor 방문자 - 객체에서 처리 분리하기
 */
// Visitor <-> Visitable 
interface Visitor {
	public void visit(Place visitable);
}
interface Place {
	public void accept(Visitor visitor);
}
@Getter @Setter
class VisitorImpl implements Visitor {
	private int number;
	public VisitorImpl() {
		this.number = 0;
	}
	@Override
	public void visit(Place place) {
		if(place instanceof PlaceImpl){
			number += ((PlaceImpl) place).getNumberOfMember();
		}else {
			//...
		}
	}	
}
@Getter @Setter
class PlaceImpl implements Place {
	private int numberOfMember;
	public PlaceImpl(int numberOfMember) {
		this.numberOfMember = numberOfMember;
	}
	@Override
	public void accept(Visitor visitor) {
		visitor.visit(this);	// visitor 에게 나 자신을 방문하도록 허락한다.
	}
}
public class _12_Main {
	public static void main(String[] args) {
		ArrayList placeList = new ArrayList();

		placeList.add(new PlaceImpl(1));
		placeList.add(new PlaceImpl(2));
		placeList.add(new PlaceImpl(3));
		placeList.add(new PlaceImpl(4));
		placeList.add(new PlaceImpl(5));

		VisitorImpl visitorImpl = new VisitorImpl();
		for (Place place : placeList) {
			place.accept(visitorImpl);
		}
		System.out.println(visitorImpl.getNumber());
	}
}

13장-1

import lombok.Getter;
import lombok.Setter;

/**
 * 13. chain of responsibility 책임 사슬
 */
@Getter @Setter
class Request {
	private int a, b;
	private String operator;
	public Request(int a, int b, String operator) {
		super();
		this.a = a;
		this.b = b;
		this.operator = operator;
	}
}
abstract class Calculator {
	private Calculator nextCaculator;
	public void setNextCalculator(Calculator nextCaculator) {
		this.nextCaculator = nextCaculator;
	}
	public boolean process(Request request) {
		if (operator(request)) {
			return true;
		} else {
			if (nextCaculator != null)
				return nextCaculator.operator(request);
		}
		return false;

		// if (preCaculator != null)
		// if(preCaculator.process(request))
		// return true;
		//
		// return operator(request);
	}
	abstract protected boolean operator(Request request);
}
class PlusCalculator extends Calculator {
	@Override
	protected boolean operator(Request request) {
		if (request.getOperator().equals("+")) {

			int a = request.getA();
			int b = request.getB();
			int result = a + b;
			System.out.println(a + "+" + b + "=" + result);
		}
		return false;
	}
}
class SubCalculator extends Calculator {
	@Override
	protected boolean operator(Request request) {
		if (request.getOperator().equals("-")) {

			int a = request.getA();
			int b = request.getB();
			int result = a - b;
			System.out.println(a + "-" + b + "=" + result);
		}
		return false;
	}
}
public class _13_1_Main {
	public static void main(String[] args) {
		Calculator plus = new PlusCalculator();
		Calculator sub = new SubCalculator();

		plus.setNextCalculator(sub);

		Request request1 = new Request(1, 2, "+"); // 3
		Request request2 = new Request(10, 2, "-");// 8

		plus.process(request1);
		plus.process(request2);
	}
}

13장-2

import lombok.Getter;
import lombok.Setter;

/**
 * 13. chain of responsibility 책임 사슬 advanced
 */
interface Defense {
	public void depense(Attack attack);
}
@Getter @Setter
class Attack {
	private int amount;
}

abstract class Armor implements Defense {
	private Defense nextDefense;
	public void setNextArmor(Defense nextDefense) {
		this.nextDefense = nextDefense;
	}
	@Override
	public void depense(Attack attack) {
		proccess(attack);
		if (nextDefense != null)
			nextDefense.depense(attack);
	}
	abstract protected void proccess(Attack attack);
}

public class _13_2_Main {
	public static void main(String[] args) {
		Attack attack = new Attack();
		attack.setAmount(100);

		Armor armorA = new Armor() {
			@Override
			protected void proccess(Attack attack) {
				int amount = attack.getAmount();
				amount *= 0.8;
				attack.setAmount(amount);
			}
		};
		Armor armorB = new Armor() {
			@Override
			protected void proccess(Attack attack) {
				int amount = attack.getAmount();
				amount -= 10;
				if (amount < 0)
					amount = 0;
				attack.setAmount(amount);
			}
		};
		armorA.setNextArmor(armorB);
		armorA.depense(attack);
		System.out.println(attack.getAmount());
		armorA.setNextArmor(new Armor() {
			@Override
			protected void proccess(Attack attack) {
				int amount = attack.getAmount();
				amount -= 50;
				if (amount < 0)
					amount = 0;
				attack.setAmount(amount);
			}
		});
		attack.setAmount(100);
		armorA.depense(attack);
		System.out.println(attack.getAmount());
	}
}

14장

/**
 * 14 facade 퍼사드 : 복잡한 과정을 간단하게 제공
 */
class HelpSystem1 {
	public HelpSystem1() {
		System.out.println("Call Constructor : " + getClass().getSimpleName());
	}
	public void process(){
		System.out.println("Call Process : "+ getClass().getSimpleName());
	}
}
class HelpSystem2 {
	public HelpSystem2() {
		System.out.println("Call Constructor : " + getClass().getSimpleName());
	}
	public void process(){
		System.out.println("Call Process : "+ getClass().getSimpleName());
	}
}
class HelpSystem3 {
	public HelpSystem3() {
		System.out.println("Call Constructor : " + getClass().getSimpleName());
	}
	public void process(){
		System.out.println("Call Process : "+ getClass().getSimpleName());
	}
}
class Facade {
	private HelpSystem1 helpSystem01;
	private HelpSystem2 helpSystem02;
	private HelpSystem3 helpSystem03;
	
	public Facade() {
		helpSystem01 = new HelpSystem1();
		helpSystem02 = new HelpSystem2();
		helpSystem03 = new HelpSystem3();
	}
	public void process(){
		helpSystem01.process();
		helpSystem02.process();
		helpSystem03.process();
	}
}
public class _14_Main {
	public static void main(String[] args) {
		Facade facade = new Facade();
		facade.process();
	}
}

15장-1

/**
 * 15. observer 상태 변화 관찰하기
 */
interface OnClickListener {
	public void onClick(Button2 button);
}
class Button2 {
	private OnClickListener onClickListener;
	public void setOnClickListener(OnClickListener onClickListener) {
		this.onClickListener = onClickListener;
	}
	public void onClick() {
		// 이벤트 처리
		if (onClickListener != null)
			onClickListener.onClick(this);
	}
}
public class _15_1_Main {
	public static void main(String[] args) {
		Button2 button = new Button2();

		button.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(Button2 button) {
				System.out.println(button + " is Clicked");
			}
		});
		button.onClick();
	}
}

15장-2

import java.util.Observable;
import java.util.Observer;

/**
 * 15 observer2
 */
class Button3 extends Observable{
	public void onClick(){
		setChanged();		// Observable
		notifyObservers();	// Observable
		
		// -------> update가 호출됨
	}
}
public class _15_2_Main {
	public static void main(String[] args) {
		Button3 button = new Button3();

		button.addObserver(new Observer() {
			@Override
			public void update(Observable o, Object arg) {
				System.out.println(o + " is Clicked");
			}
		});

		button.onClick();
		button.onClick();
		button.onClick();
	}
}

15장-3

import java.util.Vector;

/**
 * 15. observer3 - 직접구현
 */
class Button4 {
	private Observable observable;
	public Button4() {
		observable = new Observable();
	}
	public void addObserver(Observer o) {
		observable.addObserver(o);
	}
	public void notifyObservers() {
		observable.notifyObservers(null);
	}
	public void onClick() {
		observable.setChanged();
		notifyObservers();
	}
}
interface Observer {
	/**
	 * This method is called whenever the observed object is changed. An application
	 * calls an Observable object's notifyObservers method to
	 * have all the object's observers notified of the change.
	 *
	 * @param o
	 *            the observable object.
	 * @param arg
	 *            an argument passed to the notifyObservers method.
	 */
	void update(Observable o, T arg);
}
class Observable {

	private boolean changed = false;
	private Vector> obs;

	/** Construct an Observable with zero Observers. */

	public Observable() {
		obs = new Vector<>();
	}

	/**
	 * Adds an observer to the set of observers for this object, provided that it is
	 * not the same as some observer already in the set. The order in which
	 * notifications will be delivered to multiple observers is not specified. See
	 * the class comment.
	 *
	 * @param o
	 *            an observer to be added.
	 * @throws NullPointerException
	 *             if the parameter o is null.
	 */
	public synchronized void addObserver(Observer o) {
		if (o == null)
			throw new NullPointerException();
		if (!obs.contains(o)) {
			obs.addElement(o);
		}
	}

	/**
	 * Deletes an observer from the set of observers of this object. Passing
	 * null to this method will have no effect.
	 * 
	 * @param o
	 *            the observer to be deleted.
	 */
	public synchronized void deleteObserver(Observer o) {
		obs.removeElement(o);
	}

	/**
	 * If this object has changed, as indicated by the hasChanged
	 * method, then notify all of its observers and then call the
	 * clearChanged method to indicate that this object has no longer
	 * changed.
	 * 

* Each observer has its update method called with two arguments: * this observable object and null. In other words, this method is * equivalent to:

* notifyObservers(null)
* * @see java.util.Observable#clearChanged() * @see java.util.Observable#hasChanged() * @see java.util.Observer#update(java.util.Observable, java.lang.Object) */ public void notifyObservers() { notifyObservers(null); } /** * If this object has changed, as indicated by the hasChanged * method, then notify all of its observers and then call the * clearChanged method to indicate that this object has no longer * changed. *

* Each observer has its update method called with two arguments: * this observable object and the arg argument. * * @param arg * any object. * @see java.util.Observable#clearChanged() * @see java.util.Observable#hasChanged() * @see java.util.Observer#update(java.util.Observable, java.lang.Object) */ public void notifyObservers(T arg) { /* * a temporary array buffer, used as a snapshot of the state of current * Observers. */ Vector> arrLocal; synchronized (this) { /* * We don't want the Observer doing callbacks into arbitrary code while holding * its own Monitor. The code where we extract each Observable from the Vector * and store the state of the Observer needs synchronization, but notifying * observers does not (should not). The worst result of any potential * race-condition here is that: 1) a newly-added Observer will miss a * notification in progress 2) a recently unregistered Observer will be wrongly * notified when it doesn't care */ if (!changed) return; arrLocal = (Vector>) obs.clone(); clearChanged(); } for (Observer observer : arrLocal) { observer.update(this, arg); } } /** * Clears the observer list so that this object no longer has any observers. */ public synchronized void deleteObservers() { obs.removeAllElements(); } /** * Marks this Observable object as having been changed; the * hasChanged method will now return true. */ public synchronized void setChanged() { changed = true; } /** * Indicates that this object has no longer changed, or that it has already * notified all of its observers of its most recent change, so that the * hasChanged method will now return false. This method is * called automatically by the notifyObservers methods. * * @see java.util.Observable#notifyObservers() * @see java.util.Observable#notifyObservers(java.lang.Object) */ protected synchronized void clearChanged() { changed = false; } /** * Tests if this object has changed. * * @return true if and only if the setChanged method * has been called more recently than the clearChanged * method on this object; false otherwise. * @see java.util.Observable#clearChanged() * @see java.util.Observable#setChanged() */ public synchronized boolean hasChanged() { return changed; } /** * Returns the number of observers of this Observable object. * * @return the number of observers of this object. */ public synchronized int countObservers() { return obs.size(); } } public class _15_3_Main { public static void main(String[] args) { // 1. 제네릭 // 2. 델리케이트 // 3. 내부에 옵저버를 넣는다. Button4 button = new Button4(); button.addObserver(new Observer() { @Override public void update(Observable o, String arg) { System.out.println(o + " is clicked"); } }); button.onClick(); button.onClick(); button.onClick(); } }

15장-4

import java.util.Vector;

/**
 * 15. observer4 - copy?
 */
class Button5 extends Observable2{
	public void onClick(){
		setChanged();
		notifyObservers();
	}
}
interface Observer2 {
	/**
	 * This method is called whenever the observed object is changed. An
	 * application calls an Observable object's
	 * notifyObservers method to have all the object's observers
	 * notified of the change.
	 *
	 * @param o
	 *            the observable object.
	 * @param arg
	 *            an argument passed to the notifyObservers method.
	 */
	void update(Observable2 o, T arg);
}
class Observable2 {
    private boolean changed = false;
    private Vector> obs;

    /** Construct an Observable with zero Observers. */

    public Observable2() {
        obs = new Vector<>();
    }

    /**
     * Adds an observer to the set of observers for this object, provided
     * that it is not the same as some observer already in the set.
     * The order in which notifications will be delivered to multiple
     * observers is not specified. See the class comment.
     *
     * @param   o   an observer to be added.
     * @throws NullPointerException   if the parameter o is null.
     */
    public synchronized void addObserver(Observer2 o) {
        if (o == null)
            throw new NullPointerException();
        if (!obs.contains(o)) {
            obs.addElement(o);
        }
    }

    /**
     * Deletes an observer from the set of observers of this object.
     * Passing null to this method will have no effect.
     * @param   o   the observer to be deleted.
     */
    public synchronized void deleteObserver(Observer2 o) {
        obs.removeElement(o);
    }

    /**
     * If this object has changed, as indicated by the
     * hasChanged method, then notify all of its observers
     * and then call the clearChanged method to
     * indicate that this object has no longer changed.
     * 

* Each observer has its update method called with two * arguments: this observable object and null. In other * words, this method is equivalent to: *

* notifyObservers(null)
* * @see java.util.Observable#clearChanged() * @see java.util.Observable#hasChanged() * @see java.util.Observer#update(java.util.Observable, java.lang.Object) */ public void notifyObservers() { notifyObservers(null); } /** * If this object has changed, as indicated by the * hasChanged method, then notify all of its observers * and then call the clearChanged method to indicate * that this object has no longer changed. *

* Each observer has its update method called with two * arguments: this observable object and the arg argument. * * @param arg any object. * @see java.util.Observable#clearChanged() * @see java.util.Observable#hasChanged() * @see java.util.Observer#update(java.util.Observable, java.lang.Object) */ public void notifyObservers(T arg) { /* * a temporary array buffer, used as a snapshot of the state of * current Observers. */ Observer2[] arrLocal; synchronized (this) { /* We don't want the Observer doing callbacks into * arbitrary code while holding its own Monitor. * The code where we extract each Observable from * the Vector and store the state of the Observer * needs synchronization, but notifying observers * does not (should not). The worst result of any * potential race-condition here is that: * 1) a newly-added Observer will miss a * notification in progress * 2) a recently unregistered Observer will be * wrongly notified when it doesn't care */ if (!changed) return; // arrLocal = (Observer2[]) obs.toArray(); // 에러난다 arrLocal = new Observer2[obs.size()]; obs.toArray(arrLocal); clearChanged(); } for (int i = arrLocal.length-1; i>=0; i--) ((Observer2)arrLocal[i]).update(this, arg); } /** * Clears the observer list so that this object no longer has any observers. */ public synchronized void deleteObservers() { obs.removeAllElements(); } /** * Marks this Observable object as having been changed; the * hasChanged method will now return true. */ protected synchronized void setChanged() { changed = true; } /** * Indicates that this object has no longer changed, or that it has * already notified all of its observers of its most recent change, * so that the hasChanged method will now return false. * This method is called automatically by the * notifyObservers methods. * * @see java.util.Observable#notifyObservers() * @see java.util.Observable#notifyObservers(java.lang.Object) */ protected synchronized void clearChanged() { changed = false; } /** * Tests if this object has changed. * * @return true if and only if the setChanged * method has been called more recently than the * clearChanged method on this object; * false otherwise. * @see java.util.Observable#clearChanged() * @see java.util.Observable#setChanged() */ public synchronized boolean hasChanged() { return changed; } /** * Returns the number of observers of this Observable object. * * @return the number of observers of this object. */ public synchronized int countObservers() { return obs.size(); } } public class _15_4_Main { public static void main(String[] args) { Button5 button = new Button5(); button.addObserver(new Observer2() { @Override public void update(Observable2 o, Object arg) { System.out.println(o + "is Clicked"); } }); button.onClick(); button.onClick(); button.onClick(); } }

16장

import java.util.ArrayList;
import java.util.List;

/**
 * 16. mediator 중재자
 */
abstract class Colleague {
	private Mediator mediator;
	public boolean join(Mediator mediator) {
		if (mediator == null)
			return false;

		this.mediator = mediator;
		return mediator.addColleague(this);
	}
	public void sendData(String data) {
		if (mediator != null)
			mediator.mediate(data);
	}
	abstract public void handle(String data);
}
class ChatColleague extends Colleague {
	@Override
	public void handle(String data) {
		System.out.println(this+"-"+data);
	}
}
abstract class Mediator {
	protected List colleagues;
	public Mediator() {
		colleagues = new ArrayList<>();
	}
	public boolean addColleague(Colleague colleague) {
		if (colleagues != null)
			return colleagues.add(colleague);
		else
			return false;
	}
	public abstract void mediate(String data);
}
class ChatMediator extends Mediator {
	@Override
	public void mediate(String data) {
		for (Colleague colleague : colleagues) {
			//중재가능성.
			colleague.handle(data);	// 중재자가 보유한 colleague list에 모두 발송함
		}
	}
}
public class _16_Main {
	public static void main(String[] args) {
		Mediator mediator = new ChatMediator();

		Colleague colleague1 = new ChatColleague();
		Colleague colleague2 = new ChatColleague();
		Colleague colleague3 = new ChatColleague();

		colleague1.join(mediator);
		colleague2.join(mediator);
		colleague3.join(mediator);

		colleague1.sendData("AAA");
		colleague2.sendData("BBB");
		colleague3.sendData("CCC");
	}
}

17장

/**
 * 17. state - 상태패턴, 상태를 객체로 나타내기 (변화가 생긴경우만 상태체크)
 */
interface LightState {
	void on();
	void off();
}
class Light {
	protected LightState lightState;
	private LightState offState = new LightState() {
		@Override
		public void on() {
			System.out.println("Light ON");	// off->on
			lightState = onState;
		}
		@Override
		public void off() {
			System.out.println("Nothing");	// off->off : nothing
		}
	};
	private LightState onState = new LightState() {
		@Override
		public void on() {
			System.out.println("Nothing");	// on->on : nothing
		}
		@Override
		public void off() {
			System.out.println("Light OFF");	// on->off
			lightState = offState;
		}
	};
	public Light() {
		lightState = offState;
	}
	public void on() {
		lightState.on();
	}
	public void off() {
		lightState.off();
	}
}
public class _17_Main {
	public static void main(String[] args) {
		Light light = new Light();
		
		light.off();
		light.off();
		light.off();
		
		light.on();
		light.on();
		light.on();
		
		light.off();
		light.on();
		light.off();
		light.on();
		light.off();
		light.on();
	}
}

18장

import java.util.Stack;

import lombok.Getter;
import lombok.Setter;

/**
 * 18. memento 상태저장하기
 */
@Getter
class Memento {
	String state;
	protected Memento(String state) {
		this.state = state;
	}
}
@Getter @Setter
class Originator {
	String state;
	public Memento createMemento() {
		return new Memento(state);
	}
	public void restoreMement(Memento memento) {
		this.state = memento.getState();
	}
}
public class _18_Main {
	public static void main(String[] args) {
		Stack mementoStack = new Stack<>();	// FILO: first in last out

		Originator originator = new Originator();

		originator.setState("state 1");
		mementoStack.push(originator.createMemento());
		// Memento memento = new Memento();//X
		// memento.getState();//X
		originator.setState("state 2");
		mementoStack.push(originator.createMemento());
		originator.setState("state 3");
		mementoStack.push(originator.createMemento());
		originator.setState("state Final");
		mementoStack.push(originator.createMemento());

		originator.restoreMement(mementoStack.pop());
		System.out.println(originator.getState());// state Final
		originator.restoreMement(mementoStack.pop());
		System.out.println(originator.getState());// state 3
		originator.restoreMement(mementoStack.pop());
		System.out.println(originator.getState());// state 2
		originator.restoreMement(mementoStack.pop());
		System.out.println(originator.getState());// state 1
	}
}

end

'Java > POJO' 카테고리의 다른 글

lang3.StringUtils 사용예  (0) 2016.04.20