본문 바로가기

이번 포스팅에서는 디자인 패턴 정리 Java를 이용한 디자인 패턴 종류 정리를 하려고 합니다. 바로 시작하겠습니다.

인터페이스 
- 기능에 대한 선언과 구현 분리
- 기능으로  사용 통로 

기능과 분리 

	public class AinterfacesImplrement implements Ainterfaces{
		public void funcA(){
			System.out.println("기능 과 분리");
		}
	}
	
	interfcese
	
	public interface Ainterfaces {
		// 기능에 대한 선언 
		public void funcA();
	}  ⇒ 2개를한후 클래스  사용  (위에서 선언 구현)
	
	델리게이트 ( 떠넘기다 ) - 두 객체관의 관계 
	개발을 할시 다른 객체에 개발을 위임하여 사용 
	 public class Aoj{
		Ainterfces a;
		public void funcAA(){
			a.funcA();
		}
	}

 


전략 패턴 (strategy pattern)

전략 패턴 또는 정책 패턴은 실행 중에 알고리즘을 선택할 수 있게 하는 행위 소프트웨어 디자인 패턴이다. 전략 패턴은 특정한 계열의 알고리즘들을 정의하고 각 알고리즘을 캡슐화하며 이 알고리즘들을 해당 계열 안에서 상호 교체가 가능하게 만든다.

  • 여러 알고리즘을 하나의 인터페이스로 만들어 서로교환 가능하게 만듬
public class GameCharacter {
	//접근점 
	private Weapon weapon;
	
	//교한기능 
	public void setWeapon(Weapon weapon){
		this.weapon=weapon;
	}
	
	public void attack(){
		//델리케이트  : 내가 어떤걸 들고있냐에따라 출력이다름
		// 다른 클래스에게 넘김 
		weapon.attack();
	}
}

어댑터 패턴 (Adapter Pattern)

어댑터 패턴은 클래스의 인터페이스를 사용자가 기대하는 다른 인터페이스로 변환하는 패턴으로, 호환성이 없는 인터페이스 때문에 함께 동작할 수 없는 클래스들이 함께 작동하도록 해준다

이미 구현된 클래스에 adapter 의  이름으로 상속받아 요구사항에 맞게 수정한다.

단 불러오는 main 클래스같은경우 변경 x) ⇒ 많은곳에서 불러올시 변경없이 알고리즘, 파라미터 등을 바꿀 수 있어야된다. 

알고리즘을 요구사항에 맞게 변경해서 사용할 수 잇다.

public class adapterPattern {
	// 수의 두배 반환  수의 반의수를 반환 구현 객체이름 addapter  요구사항 float
	// 메인 함수의 수정 x ==> 여러 곳에서 가저와야할시 가저오는곳은 변경 x 
	public static void main(String[] args) {
		AdapterImpl adapter = new AdapterImpl();
		System.out.println(adapter.twiceOf(100f));
		System.out.println(adapter.halfOf(80f));
	}
}
// 기존 클래스
class Math{
	//두배 절반
	public static double twoTime(double num){return num*2; }
	public static double half(double num){return num/2; }
	// 강화된 알고리즘
	public static Double doubled(Double d){return d*2;} // 알고리즘이 바꼇다고 가정 
}

interface Adapter{
	// 원하는 기능 요청
	public Float twiceOf(Float f);
	public Float halfOf(Float f);
}
// 요청 해결을 위해 
class AdapterImpl implements Adapter{  
	@Override
//	public Float twiceOf(Float f) {
//		return (float)Math.twoTime(f.doubleValue());
//	}
	// 알고리짐으 바뀐걸 가정하여 위의 수의 변경 필요 
	public Float twiceOf(Float f){
		return Math.doubled(f.doubleValue()).floatValue();
	} // 매인함수의 변경 없이 바뀐 알고리즘을 수정 

	@Override
	public Float halfOf(Float f) {// 로그기록도 요청시
		System.out.println("절반 함수 호출 시작 ");
		return (float)Math.half(f.doubleValue());
	}
}

템플릿 메소드 패턴 (Template Method Pattern)

템플릿 메소드 패턴은 소프트웨어 공학에서 동작 상의 알고리즘의 프로그램 뼈대를 정의하는 행위 디자인 패턴이다. 알고리즘의 구조를 변경하지 않고 알고리즘의 특정 단계들을 다시 정의할 수 있게 해준다.

일정한 프로세스를 가진 요구사항을 묶어주는 패턴

-       구현하려는 알고리즘이 일정한 프로세스가 있다. (여러 단계로 나눌 수 있다)

-       구현하려는 알고리즘의 변경 가능성이 있다.

사용 단계

  1. 알고리즘을 여러 단계로 나눈다.
  2. 나눠진 알고리즘 단계를 메소드를 선언한다.
  3. 알고리즘을 수행할 템플릿 메소드를 만든다.
  4. 하위 클래스에서 나눠진 메소드들을 구현한다.

아래 예시에서 추가사항 있을시  하위 클래스에서 알고리즘 구조의 변경없이 알고리즘을 변경한다 .

public class Template_Method_Pattern {  // 원래 다른 패키지에서 가저와야 함 
	public static void main(String[] args) {
		// 접속시 보안 인증 권한 접속 과정으로 나눠서 접근해야함 ==> 요청사항
		AbstGameConnectHelper helper = new DefaultGameconnectHelpler();
		helper.requestConnection("idandpassword");
		//추가요청 보안강화 + 10시 셧다운 
	}
}

abstract class AbstGameConnectHelper {
	protected abstract String doSecurity(String string);

	protected abstract boolean authentication(String id, String password);

	protected abstract int authorization(String userName);

	protected abstract String connection(String info);

	// 템플릿 메소드
	public String requestConnection(String encodedInfo) {
		// 보안작업 -> 암호화된 문자열을 디코드
		String decodedInfo = doSecurity(encodedInfo);
		String id = "aa";
		String password = "bbb"; // 디코딩 한걸로 수신했다고 가정
		// 반환된 것을 가지고 id,password 를 받음

		if (!authentication(id, password)) {
			System.out.println("암호 불일치");
		}

		String userName = "userName";
		// 인증 성공시
		
		//권한획득 
		int i = authorization(userName);
		
		switch(i){
		case -1:
			throw new Error("10시 셧다운");
		case 0: //게임메니저
			System.out.println();
			break;
		case 1: //유료 회원
			break;
		case 2: //무료회원
			break;
		case 3: //권한 없음
			break;
			default://기타사항
				break;
		}
		return connection(userName);
	}
}

class DefaultGameconnectHelpler extends AbstGameConnectHelper{

	@Override
	protected String doSecurity(String string) {
		// 추가요청사항 
		System.out.println("강화된 알고리즘 ");
		System.out.println("디코드");
		return string;
	}

	@Override
	protected boolean authentication(String id, String password) {
		System.out.println("아이디 암호 확인과정");
		return true;
	}

	@Override
	protected int authorization(String userName) {
		// 추가요청 10시이후 
		System.out.println("서버에서 나이를 불러와 확인후 시간과 비교 ");
		System.out.println("권한 확인");
		return 0;
	}

	@Override
	protected String connection(String info) {
		System.out.println("마지막 접속 단계");
		return info;
	}
	
}


팩토리 메소드 패턴 FactoryMethodPattern

팩토리 메서드 패턴은 객체지향 디자인 패턴이다. Factory method는 부모 클래스에 알려지지 않은 구체 클래스를 생성하는 패턴이며. 자식 클래스가 어떤 객체를 생성할지를 결정하도록 하는 패턴이기도 하다. 부모 클래스 코드에 구체 클래스 이름을 감추기 위한 방법으로도 사용한다

  • 여기에서는 템플릿 메소드 패턴이 사용됨
  • 구조와 구현의 분리

장점

  1. 다른 값을 생성시 Creator 와 Item 을 구현시 다른 값을 만들 필요가 없음

  2. 접근하는 클래스에서 변경 할 필요 없음

import java.sql.Date;

public class FactoryMethodPattern {
	public static void main(String[] args) {
		// 요구사항  게임 아이템 과 생성을 구현 -> 아이템을 생성전 db에서 아이템정보를 요청
		// 아이템 생성후 db에 아이템 생성정보를 남김 
		ItemCreator creator;
		Item item;
		
		creator = new HpCreator();
		item = creator.create();
		creator= new MpCreator();
		creator.create();
	}
}

abstract class ItemCreator{ //template method pattern 처럼 됨 
	public Item create(){
		Item item;
		requestItemInfo();
		item = createItem();
		createItemLog();
		
		return item;
	}
	// 아이템 생성전 아이템 정보를 요청
	abstract protected void requestItemInfo();
	// 아이템 정보 남김
	abstract protected void createItemLog();
	//아이템을 생성하는 알고리즘
	abstract protected Item createItem();
}
// 팩토리 메소드 -> 템플릿 메소드
interface Item{
	public void use();
}

class HpPotion implements Item{

	@Override
	public void use() {
		System.out.println("체력회복 ");
	}
	
}

class MpPotion implements Item{

	@Override
	public void use() {
		System.out.println("마력회복");
	}
	
}

class HpCreator extends ItemCreator{

	@Override
	protected void requestItemInfo() {
		System.out.println("db에서 체력  회복 물략의 정보를 가저옴 ");
		
	}

	@Override
	protected void createItemLog() {
		System.out.println("체력 회복 물약을 새로 생성 했습니다."+ new Date(0));
	}

	@Override
	protected Item createItem() {
		// 작업 .... 
		return new HpPotion();
	}
	
}


class MpCreator extends ItemCreator{

	@Override
	protected void requestItemInfo() {
		System.out.println("db에서 마력 회복 물략의 정보를 가저옴 ");
		
	}

	@Override
	protected void createItemLog() {
		System.out.println("마력 회복 물약을 새로 생성 했습니다."+ new Date(0));
	}

	@Override
	protected Item createItem() {
		// 작업 .... 
		return new MpPotion();
	}
	
}

싱글톤 패턴 (singeton pattern)

소프트웨어 디자인 패턴에서 싱글턴 패턴을 따르는 클래스는, 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴한다. 이와 같은 디자인 유형을 싱글턴 패턴이라고 한다

하나의 인스턴스만 생성하도록 구현 할 수 있음.

  • 객체 : 속성과 기능을 갖춘것
  • 클래스 : 속성과 기능을 정의한 것
  • 인스턴스 : 속성과 기능을 가진것 중 실제 하는것
public class SingletoePattern {
	public static void main(String[] args) {
		// 기본 : 개발 중인 시스템에서 스피커에 접근 할 수 있는 클래스를 만들기 ==> 100개의 스피커 모두 볼륨오릴기
		// 추가요청 : 인스턴스를 추가시마다 로그를 직음 
		//new 로 하면안됨
		SystemSpeaker speaker1 = SystemSpeaker.getInstance();
		SystemSpeaker speaker2 = SystemSpeaker.getInstance();
		
		System.out.println(speaker1.getVolume());
		System.out.println(speaker2.getVolume());
		
		speaker1.setVolume(11);
		System.out.println(speaker1.getVolume());
		System.out.println(speaker2.getVolume());
		
		speaker2.setVolume(22);
		System.out.println(speaker1.getVolume());
		System.out.println(speaker2.getVolume());
	}
}

class SystemSpeaker{
	static private SystemSpeaker instantce;
	private int volume;
	private SystemSpeaker(){
		setVolume(5);
	}
	public static SystemSpeaker getInstance(){
		if(instantce==null){
			//시스템의 스피커에 접속
			instantce= new SystemSpeaker();
			//추가요청
			System.out.println("새로생성");
		}
		//추가요청
		System.out.println("이미생성");
		return instantce;
		
	
	}
	
	public int getVolume() {
		return volume;
	}
	public void setVolume(int volume) {
		this.volume = volume;
	}

프로토타입 패턴 (PrototypePattern)

프로토타입 패턴은 소프트웨어 디자인 패턴 용어로, 생성할 객체들의 타입이 프로토타입인 인스턴스로부터 결정되도록 하며, 인스턴스는 새 객체를 만들기 위해 자신을 복제하게 된다. 

복잡한 인스턴스를 복사

  • 생산 비용이 높은 인스턴스를 사용
  • 종류가 너무 많아서 클래스로 정리되지 않는 경우
  • 클래스로부터 인스턴스 생성이 어려운 경우
public class PrototypePattern {
	public static void main(String[] args) throws CloneNotSupportedException {
		// 축다요청 복사를하면 도형이 겹침으로 안겹치도록 살짝 이동 ㅛㅇ청
		Circle circle1 = new Circle(1,1,3);
		Circle circle2 = circle1.copy();
		System.out.println(circle1.getX()+","+circle1.getY()+","+circle1.getR());
		System.out.println(circle2.getX()+","+circle2.getY()+","+circle2.getR());
			}
}

//java 에서는 명시적으로 써줘야
class Shape implements Cloneable{
	private String id;  // 모양을 id 를 통해서 만듬 

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}
	
}

// 꼭 extends 해줘야함
class Circle extends Shape{
	private int x,y,r;
	
	/**
	 * @param x
	 * @param y
	 * @param r
	 */
	
	public Circle(int x, int y, int r) {
		super();
		this.x = x;
		this.y = y;
		this.r = r;
	}

	public Circle copy() throws CloneNotSupportedException{
		Circle circle = (Circle)clone();
		// 추가요청 사항 접수 circle 이 복잡한경우 복사가 힘들어서  clone 이 일아서해줌  한번씩만 더해주면됨 
		circle.x++;
		circle.y++;
		circle.r++;
		return circle;
	}

	public int getR() {
		return r;
	}

	public void setR(int r) {
		this.r = r;
	}

	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 class PrototypePattern2 {
	public static void main(String[] args) throws CloneNotSupportedException {
		//  깊은 복사와 얕은 복사 
		Cat na = new Cat();
		na.setName("na"); // 나비설정
		na.setAge(new Age(2012,3));
		// 나비를 복사하여 새로운이름생성
		Cat y = na;
		y.setName("yo");
		y.setAge(new Age(2013,2));
		// 두개의 주소가 같아서 하나수정시 두개다 바뀜 ==> 앝은 복사
		System.out.println(na.getName() + "," + na.getAge().getYear());
		System.out.println(y.getName() + "," + y.getAge().getYear());
		na = y.copy(); // 깊은 복사 
		na.setName("navi"); // 변견된것을 확인 가능
		na.setAge(new Age(2012,3));
		System.out.println(na.getName() + "," + na.getAge().getYear());
		System.out.println(y.getName() + "," + y.getAge().getYear());
		
		//깊은 복사가 잃어나지 않음 ==> 자동으로 새로운 주소값으로 참조함 
		y.setName("yo2");
		y.getAge().setYear(2017);
		y.getAge().setValue(7);
		System.out.println(na.getName() + "," + na.getAge().getYear());
		System.out.println(y.getName() + "," + y.getAge().getYear());
		// 깊은복사를 위해서는 CAT 클래스에서 해야함 
	}
}

class Cat implements Cloneable {
	private String name;
	private Age age;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Cat copy() throws CloneNotSupportedException {
		Cat ret = (Cat) this.clone();
		// main에서 마지막 예시의 깊은 복사를 위해   아래 추가하면 명시적 깊은복사 출력값달라짐 
		//ret.setAge(new Age(this.age.getYear(), this.age.getValue()));
		return ret;
	}

	public Age getAge() {
		return age;
	}

	public void setAge(Age age) {
		this.age = age;
	}
}

class Age {
	private int year;
	private int value;

	public int getYear() {
		return year;
	}

	public Age(int year, int value) {
		super();
		this.year = year;
		this.value = value;
	}

	public void setYear(int year) {
		this.year = year;
	}

	public int getValue() {
		return value;
	}

	public void setValue(int value) {
		this.value = value;
	}


빌더 패턴 BuilderPattern

빌더 패턴이란 복합 객체의 생성 과정과 표현 방법을 분리하여 동일한 생성 절차에서 서로 다른 표현 결과를 만들 수 있게 하는 패턴이다. 

복잡한 단계가 필요한 인스턴스 생성을 빌더 패턴을 통해서 구현할 수 있다.

  • 서브 클래스에게 복잡한 다계를 거쳐야 샹성되는 개체의 구현을 넘겨주는 패턴
  • 많은 인자를 가진 객체의 생성을 도움받아 생성
public class BuilderPattern {
	public static void main(String[] args) {
		Computer computer = new Computer("i7","16G","256SSD");
		System.out.println(computer.toString());
		//인자 값이 많아질 경우 출력 힘들고 복잡해짐
		// ==> 생성을 다른 객체로 넘김
		ComputerFactory factory = new ComputerFactory();
		factory.setPrint(new LgGramBlueprint());
		factory.make();
		// 설계 도를 만들어서 가지고옴 
		Computer computer4 = factory.getComputer();
		System.out.println(computer.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;
	}

	public String getCpu() {
		return cpu;
	}

	public void setCpu(String cpu) {
		this.cpu = cpu;
	}

	public String getRam() {
		return ram;
	}

	public void setRam(String ram) {
		this.ram = ram;
	}

	public String getStorage() {
		return storage;
	}

	public void setStorage(String storage) {
		this.storage = storage;
	}

	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return cpu + "," + ram + "," + storage;
	}
}

abstract class BluePrint {
	abstract public void setCpu();

	abstract public void setRam();

	abstract public void setStorage();
	
	abstract Computer getComputer();
}

class LgGramBlueprint extends BluePrint {
	private Computer computer;

	public LgGramBlueprint() {
		computer = new Computer("default", "default", "default");
	}

	@Override
	public void setCpu() {
		computer.setRam("i7");
	}

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

	@Override
	public void setStorage() {
		computer.setStorage("246SSD");

	}

	@Override
	Computer getComputer() {
		// TODO Auto-generated method stub
		return computer;
	}

}


class ComputerFactory{
	private BluePrint print;
	// 방법2 여기서 인자값을 private String cpu ram 만들고 직접 값을넣어준후 
	public void setPrint(BluePrint print) {
		this.print = print;
	}
	public void make(){
		print.setCpu();
		print.setRam();
		print.setStorage();
	}
	public Computer getComputer(){
		// 여기에서 new로 만들어서 리턴해도됨 
		return print.getComputer();
	}
	
}

 

또 다른 예시

public class BuilderPattern2 {
	public static void main(String[] args) {
		// Computer computer = new Computer("","",""); // 값의 순서를 잘못 입력했을 경우의
		// 문제도잇음 ==> 값이많을대는 해깔림
		Computer computer2 = ComputerBuilder
				//.start()
				//.setCpu("i7")
				.startWithCpu("i7") // 위 2개와는 달리 시작과 동시에 cpu정보를 넣어 줄 수도 잇음 
				.setRam("8G") // 초기화하는 명칭을 알 수 있음 
				.setStorage("128G SSD")
				.build();

		System.out.println(computer2.toString());
	}
}

class Computer {
	private String cpu;
	private String ram;
	private String storage;

	/*
	 * @param cpu 입니다.
	 * 
	 * @param rma 입니다.
	 * 
	 * @param storage 입니다.
	 */

	public Computer(String cpu, String ram, String storage) { // 변수값이 엄청 많을대
		super();
		this.cpu = cpu;
		this.ram = ram;
		this.storage = storage;
	}

	public String getCpu() {
		return cpu;
	}

	public void setCpu(String cpu) {
		this.cpu = cpu;
	}

	public String getRam() {
		return ram;
	}

	public void setRam(String ram) {
		this.ram = ram;
	}

	public String getStorage() {
		return storage;
	}

	public void setStorage(String storage) {
		this.storage = storage;
	}

	@Override
	public String toString() {
		// TODO Auto-generated method stub
		return cpu + "," + ram + "," + storage;
	}

}

class ComputerBuilder {
	private Computer computer;

	private ComputerBuilder() {
		computer = new Computer("default", "default", "default");
	}

	public static ComputerBuilder start() {
		return new ComputerBuilder();
	}
	public static ComputerBuilder startWithCpu(String cpu){
		ComputerBuilder builder = new ComputerBuilder();
		builder.computer.setCpu(cpu);
		return builder;
	}
	 // 시작과 동시에 cpu 를 넣어 줄수도 있음 
	public ComputerBuilder setCpu(String string) {
		computer.setCpu(string);
		return this;
	}

	public ComputerBuilder setRam(String string) {
		computer.setRam(string);
		return this;
	}

	public Computer build() {
		return this.computer;
	}
	
	public ComputerBuilder setStorage(String storage){
		computer.setStorage(storage);
		return this;
	}

 

이상으로 Java 소스를 이용한 디자인 패턴 정리 1편을 마치도록 하겠습니다.

2020/07/31 - [IT/Java] - [디자인 패턴] Java를 이용한 소스로 보는 디자인 패턴 종류 정리 2편

 

[디자인 패턴] Java를 이용한 소스로 보는 디자인 패턴 종류 정리 2편

이번 포스팅에서는 디자인 패턴 정리 Java를 이용한 디자인 패턴 종류 정리를 하려고 합니다. 바로 시작하겠습니다. 2020/07/30 - [IT/Java] - [디자인 패턴] Java를 이용한 소스로 보는 디자인 패턴 종류

kingname.tistory.com

 

엉망진창

개인 블로그 입니다. 코딩, 맛집, 정부정책, 서비스, ~방법 등 다양한 정보를 소개합니다