Design Patterns - Sizuha/devdog GitHub Wiki

๋””์ž์ธ ํŒจํ„ด์—์„œ ๋ฐฐ์šฐ๋Š” ์„ค๊ณ„ ์›์น™

  • if(switch ํฌํ•จ) ๋Œ€์‹  ์ƒ์†๊ณผ ๋‹คํ˜•์„ฑ ํ™œ์šฉํ•œ๋‹ค
  • ์ธํ„ฐํŽ˜์ด์Šค ์ค‘์‹ฌ ์„ค๊ณ„
    • ๋ณ€๊ฒฝ์ด ๋ฐœ์ƒ๋  ๋ถ€๋ถ„์— ๋Œ€ํ•ด, ์‚ฌ์šฉ์ž๋ฅผ ์œ„ํ•œ ๊ณตํ†ต๋œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•˜๊ณ , ์„ธ๋ถ€์ ์ธ ๋‚ด์šฉ์€ ๊ทธ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์† ๋ฐ›์•„์„œ ๊ตฌํ˜„ํ•˜์—ฌ ๋ฏธ๋ž˜์˜ ๋ณ€๋™์‚ฌํ•ญ์— ๋Œ€๋น„ํ•œ๋‹ค.

๊ฐ์ฒด ์ƒ์„ฑ์— ๊ด€ํ•œ ํŒจํ„ด

๊ณตํ†ต์˜ ๋ฌธ์ œ์ƒํ™ฉ : ์˜ˆ์‹œ

๊ฒŒ์ž„์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๊ฒŒ์ž„ ์บ๋ฆญํ„ฐ๋ฅผ ์ •์˜ํ•œ Character Class๊ฐ€ ์žˆ๋‹ค.

๊ฒŒ์ž„ ์บ๋ฆญํ„ฐ๋Š” ์ „์‚ฌ(Fighter), ๊ถ์ˆ˜(Archer), ๋งˆ๋ฒ•์‚ฌ(Wizard)๋กœ ๊ฐ๊ฐ ์ง์—…์ด ๊ตฌ๋ถ„๋˜์–ด ์žˆ๋‹ค.

ํ”Œ๋ ˆ์ด์–ด๋Š” ์ด๋“ค ์ง์—… ์ค‘์— ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•ด์„œ ํ”Œ๋ ˆ์ด ํ•˜๊ฒŒ ๋œ๋‹ค.

์ด๊ฒƒ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•œ ์ ์ ˆํ•œ ์„ค๊ณ„๋ฅผ ์ฐพ์•„๋ณด์ž.

Abstract Factory

๋ฌธ์ œ ์ƒํ™ฉ

  • ์ œํ’ˆ๊ตฐ์˜ ์กด์žฌ
    • ์—ฌ๋Ÿฌ ์ข…๋ฅ˜์˜ ๊ฐ์ฒด๋“ค์ด ์กด์žฌํ•˜๋Š” ์ƒํƒœ์—์„œ,๊ทธ ๊ฐ์ฒด๋“ค์ด ๋‹ค์‹œ ์—ฌ๋Ÿฌ ์ข…๋ฅ˜์˜ ์ œํ’ˆ๊ตฐ์œผ๋กœ ๊ทธ๋ฃนํ™” ๋˜๋Š” ๊ฒฝ์šฐ
  • ์ œํ’ˆ๊ตฐ์ด ์กฐํ•ฉ๋˜์–ด์ง€๋Š” ๊ฒฝ์šฐ์˜ ์ˆ˜๊ฐ€ ๋งŽ์•„์งˆ ๊ฒฝ์šฐ์— ๋Œ€ํ•œ ๋ฌธ์ œ.

๊ตฌํ˜„

์•ž์— ๋‚˜์˜จ ๊ณตํ†ต์˜ ๋ฌธ์ œ์ƒํ™ฉ์„ ์˜ˆ๋กœ ๋“ค๋ฉด,

// ๊ฒŒ์ž„ ์บ๋ฆญํ„ฐ์— ๋Œ€ํ•œ ๊ณตํ†ต์˜ ์ •์˜
class Character {
	public Vector2 position; // ์บ๋ฆญํ„ฐ์˜ ํ˜„์žฌ ์œ„์น˜
	public int hp; 

	public Character(int hp) {
		this.hp = hp;
	}

	public float getDistanceFrom(Character target) {
		return Math.sqrt( Math.pow(target.position.x - this.position.x, 2) + Math.pow(target.position.y - this.position.y, 2) );
	}

	public void defense(int damage) {
		hp -= damage;
	}	
}


interface Weapon {
	int getAttackRange();
	int getDamage();
}

class Sword : Weapon {
	public int getAttackRange() { return 1; }
	public int getDamage() { return 10; }
}

class Bow : Weapon {
	public int getAttackRange() { return 5; }
	public int getDamage() { return 5; }	
}

class Staff : Weapon {
	public int getAttackRange() { return 5; }
	public int getDamage() { return 5; }	
}


interface Defender {
	int getDef();
}

class NoneDefense : Defender {
	public int getDef() { return 0; }
}

class Shield : Defender {
	public int getDef() { return 2; }
}

class MagicShield : Defender {
	public int getDef() { return 1; }
}


//----- ํ”Œ๋ ˆ์ด์–ด์˜ ์•ก์…˜์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ถ€๋ถ„ -------
class GameManager {

	public void attack(Character atkChr, Character defChr) {
		var distance = atkChr.getDistanceFrom(defChr);
		if (distance <= atkChr.weapon.getAttackRange()) {
			var damage = atkChr.weapon.getDamage() - defChr.defender.getDef();
			defChr.defense(damage);
		}
	}

}

์ด์ œ ํ”Œ๋ ˆ์ด์–ด๊ฐ€ ์ž์‹ ์ด ์„ ํƒํ•œ ์ง์—…์— ๋Œ€ํ•ด์„œ, ๊ทธ์— ๋งž๋Š” ์บ๋ฆญํ„ฐ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์ง์—…๋ณ„๋กœ ๋ฌด๊ธฐ์™€ ๋ฐฉ์–ด๊ตฌ๋ฅผ ์ƒ์„ฑํ•ด ์ฃผ์–ด์•ผ ํ•œ๋‹ค. ํ•˜์ง€๋งŒ, ๊ทธ์™ธ ๊ณต๊ฒฉ์ด๋‚˜ ๋ฐฉ์–ด์— ๋Œ€ํ•œ ๋กœ์ง์„ ๋ณ€ํ•จ์ด ์—†๋‹ค.

์ด๋•Œ ์บ๋ฆญํ„ฐ ์ง์—…์„ ํ•˜๋‚˜์˜ ์ œํ’ˆ๊ตฐ์œผ๋กœ ๋ณด๊ณ , ๊ฐ ์ง์—…๋ณ„๋กœ ํŒฉํ† ๋ฆฌ ํด๋ž˜์Šค๋ฅผ ํ•˜๋‚˜์”ฉ ์ •์˜ํ•ด ๋‚˜๊ฐ„๋‹ค.

// ์ œํ’ˆ๊ตฐ์— ๋Œ€ํ•œ ์ธํ„ฐํŽ˜์ด์Šค
interface PlayerJobFactory {
	Character createCharacter();
	Weapon createWeapon();
	Defender createDefender();
}

class FighterFactory : PlayerJobFactory {
	public Character createCharacter() { new Character(200); }
	public Weapon createWeapon() { new Sword(); }
	public Defender createDefender() { new Shield(); }
}

class ArcherFactory : PlayerJobFactory {
	public Character createCharacter() { new Character(150); }
	public Weapon createWeapon() { new Bow(); }
	public Defender createDefender() { new NoneDefense(); }
}

class WizardFactory : PlayerJobFactory {
	public Character createCharacter() { new Character(100); }
	public Weapon createWeapon() { new Staff(); }
	public Defender createDefender() { new MagicShield(); }
}

Factory Method

๋ฌธ์ œ ์ƒํ™ฉ

  • ์–ด๋А ํ•œ ํด๋ž˜์Šค ๋‚ด์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๋Œ€์ƒ ๊ฐ์ฒด๊ฐ€ ์—ฌ๋Ÿฌ ์ข…๋ฅ˜๊ฐ€ ์žˆ๊ณ ,
  • ๊ทธ ์ค‘์—์„œ ๊ฒฝ์šฐ์— ๋”ฐ๋ผ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•ด์„œ ์ƒ์„ฑํ•˜๊ฒŒ ๋˜๋Š” ๊ฒฝ์šฐ
    • ์ฆ‰, ๊ฐ์ฒด ์ƒ์„ฑ๊ณผ์ •์—์„œ ๊ฒฝ์šฐ์˜ ์ˆ˜๊ฐ€ ๋ฐœ์ƒ

๊ตฌํ˜„

์ƒ์œ„์˜ ์ถ”์ƒ ํด๋ž˜์Šค์—์„œ ๊ฐ์ฒด ์ƒ์„ฑ์„ ์œ„ํ•œ ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“ค์–ด ๋‘๊ณ , ์‹ค์ œ ๊ฐ์ฒด์˜ ์ƒ์„ฑ์€ ํ•˜์œ„ ํด๋ž˜์Šค์˜ ํŒฉํ† ๋ฆฌ ๋ฉ”์†Œ๋“œ์—์„œ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ํ•œ๋‹ค.

// ๊ฒŒ์ž„ ์บ๋ฆญํ„ฐ์— ๋Œ€ํ•œ ๊ณตํ†ต์˜ ์ •์˜
abstract class Character {
	public Vector2 position; // ์บ๋ฆญํ„ฐ์˜ ํ˜„์žฌ ์œ„์น˜
	public int hp; 

	Weapon weapon;
	Defender defender;

	public Character(int hp) {
		this.hp = hp;

		weapon = createWeapon();
		defender = createDefender();
	}

	abstract protected Weapon createWeapon();
	abstract protected Defender createDefender();

	public float getDistanceFrom(Character target) {
		return Math.sqrt( Math.pow(target.position.x - this.position.x, 2) + Math.pow(target.position.y - this.position.y, 2) );
	}

	public void defense(int damage) {
		hp -= damage - defender.getDef();
	}	

	public void attack(Character defChr) {
		var distance = getDistanceFrom(defChr);
		if (distance <= weapon.getAttackRange()) {
			var damage = weapon.getDamage();
			defChr.defense(damage);
		}
	}

}


//---- ์ง์—…๋ณ„ ์ •์˜ -------
class Fighter : Character {
	public Fighter() : base(200) {}
	protected Weapon createWeapon() { return new Sword();}
	protected Defender createDefender() { new Shield(); }
}

class Archer : Character {
	public Archer() : base(150) {}
	protected Weapon createWeapon() { return new Bow();}
	protected Defender createDefender() { new NoneDefense(); }	
}

class Wizard : Character {
	public Wizard() : base(100) {}
	protected Weapon createWeapon() { return new Staff();}
	protected Defender createDefender() { new MagicShield(); }	
}

Builder

๋ฌธ์ œ ์ƒํ™ฉ

  • ๊ฐ์ฒด ์ƒ์„ฑ์— ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•˜๋Š” ์‹œ์ ๊ณผ, ์‹ค์ œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์•ผ ๋˜๋Š” ์‹œ์ ์— ๊ฒฉ์ฐจ๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ,
    • ๊ฐ์ฒด ์ƒ์„ฑ ๊ณผ์ •์„ ๋‹จ๊ณ„์ ์œผ๋กœ ์ง„ํ–‰ํ•˜๊ฒŒ ํ•ด์•ผ๋˜๋Š” ๊ฒฝ์šฐ
  • ๊ฐ์ฒด ์ƒ์„ฑ ๊ณผ์ •์—์„œ, ๋‹ค์–‘ํ•œ ์˜ต์…˜์„ ๋ถ€์—ฌํ•ด์•ผ ๋˜๋Š” ๊ฒฝ์šฐ

๊ตฌํ˜„

  • ๋ชฉ์ ์ด ๋˜๋Š” ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ๋นŒ๋” ํด๋ž˜์Šค๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค.
  • ๋นŒ๋” ํด๋ž˜์Šค๋Š” ๋ชฉ์  ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•œ ์ •๋ณด๋ฅผ ์…‹ํŒ…ํ•˜๊ธฐ ์œ„ํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณต.
  • ์ตœ์ข…์ ์œผ๋กœ ์ง์ „๊นŒ์ง€ ์ˆ˜์ง‘๋œ ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ๋ชฉ์  ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ๋ฉ”์†Œ๋“œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.
class Character {
	public string name;
	public Vector2 position; // ์บ๋ฆญํ„ฐ์˜ ํ˜„์žฌ ์œ„์น˜
	public int hp; 

	public Weapon weapon;
	public Defender defender;

	public Character(string name, Vector2 position, int hp, Weapon weapon, Defender defender) {
		// ...
	}

	public float getDistanceFrom(Character target) {
		return Math.sqrt( Math.pow(target.position.x - this.position.x, 2) + Math.pow(target.position.y - this.position.y, 2) );
	}

	public void defense(int damage) {
		hp -= damage - defender.getDef();
	}	

	public void attack(Character defChr) {
		var distance = getDistanceFrom(defChr);
		if (distance <= weapon.getAttackRange()) {
			var damage = weapon.getDamage();
			defChr.defense(damage);
		}
	}

}


class ChracterBuilder {

	string name;
	int hp;
	Vector2 pos;
	Weapon w;
	Defender d;

	public ChracterBuilder() {}

	public ChracterBuilder setName(string name) { this.name = name; return this; }
	public ChracterBuilder setHP(int hp) { this.hp = hp; return this; }
	public ChracterBuilder setPosition(Vector2 pos) { this.pos = pos; return this; }
	public ChracterBuilder setWeapon(Weapon weapon) { w = weapon; return this; }
	public ChracterBuilder setDefender(Defender defender) { d = defender; return this; }

	public Character createCharacter() {
		return new Character(name, pos, hp, w, d);
	}

}


// ์‚ฌ์šฉ์˜ˆ:
void createFighter() {
	Character player =
		new ChracterBuilder()
		.setName("Player")
		.setHP(200)
		.setWeapon(new Sword())
		.setDefender(new Shield())
		.createCharacter();

	// . . .
}

MVC

MVCใฎๅ…ธๅž‹็š„ใช็›ธ้–ขๅ›ณ MVC๏ผˆModel View Controller ใƒขใƒ‡ใƒซใƒปใƒ“ใƒฅใƒผใƒปใ‚ณใƒณใƒˆใƒญใƒผใƒฉ๏ผ‰ใฏใ€ใƒฆใƒผใ‚ถใƒผใ‚คใƒณใ‚ฟใƒ•ใ‚งใƒผใ‚นใ‚’ใ‚‚ใคใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใ‚ฝใƒ•ใƒˆใ‚ฆใ‚งใ‚ขใ‚’ๅฎŸ่ฃ…ใ™ใ‚‹ใŸใ‚ใฎใƒ‡ใ‚ถใ‚คใƒณใƒ‘ใ‚ฟใƒผใƒณใงใ‚ใ‚‹ใ€‚

ใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใ‚ฝใƒ•ใƒˆใ‚ฆใ‚งใ‚ขใฎๅ†…้ƒจใƒ‡ใƒผใ‚ฟใ‚’ใ€ใƒฆใƒผใ‚ถใƒผใŒ็›ดๆŽฅๅ‚็…งใƒป็ทจ้›†ใ™ใ‚‹ๆƒ…ๅ ฑใ‹ใ‚‰ๅˆ†้›ขใ™ใ‚‹ใ€‚ใใฎใŸใ‚ใซใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใ‚ฝใƒ•ใƒˆใ‚ฆใ‚งใ‚ขใ‚’ไปฅไธ‹ใฎ3ใคใฎ้ƒจๅˆ†ใซๅˆ†ๅ‰ฒใ™ใ‚‹ใ€‚

  • model: ใ‚ขใƒ—ใƒชใ‚ฑใƒผใ‚ทใƒงใƒณใƒ‡ใƒผใ‚ฟใ€ใƒ“ใ‚ธใƒใ‚นใƒซใƒผใƒซใ€ใƒญใ‚ธใƒƒใ‚ฏใ€้–ขๆ•ฐ
  • view: ใ‚ฐใƒฉใƒ•ใ‚„ๅ›ณใชใฉใฎไปปๆ„ใฎๆƒ…ๅ ฑ่กจ็พ
  • controller: ๅ…ฅๅŠ›ใ‚’ๅ—ใ‘ๅ–ใ‚Šmodelใจviewใธใฎๅ‘ฝไปคใซๅค‰ๆ›ใ™ใ‚‹