Skip to content

Latest commit

 

History

History

Strategy

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 

Ch.1 디자인 패턴과 전략 패턴

오리 시뮬레이션 설계

  1. Duck 슈퍼클래스 생성, 오리들은 이 클래스를 상속
abstract class Duck {
   quack() { "꽥꽥" }   // 모든 오리는 꽥꽥거리고 물에 뜨므로 미리 구현
   swim() { "수영" }
   display() // 모양은 서로 다르기 때문에 추상메소드
 }
class MallardDuck : Duck {
	override fun display()
}

class RedHeadDuck : Duck {
	override fun display()
}

-> 오리가 날 수 있도록 해주세요!

abstract class Duck {
   quack() { "꽥꽥" }
   swim() { "수영" }
   display()
   fly()   // 이걸 추가하면 되지않을까?
 }

문제점1 :
일부 서브클래스는 필요하지 않은 기능도 상속받게 됨 (슈퍼클래스의 코드 변경 시 원치 않은 영향을 끼칠 수 있음)

-> 고무오리가 날게 되는 불상사가 발생한다.

class RubberDuck : Duck {
	override fun quack() { "삑삑" } // 삑삑으로 오버라이드 
	override fun fly() {  } // 아무것도 하지 않도록 오버라이드
	override fun display() 
 }

문제점2: 필요하지 않은 기능을 작동하지 않도록 오버라이드 (서브클래스에서 코드가 중복됨, 어떤 클래스에서 어떤 오버라이드 중인지 매번 확인해야함)


  1. 해당 기능들을 Behavior 인터페이스로 분리
abstract class Duck {
	swim()
	display()
 }
 
 interface Flyable {
	fly()
 }
 
interface Quackable {
	quack()
 }
class MallardDuck : Duck, Flayable, Quackable {
	override fun display()
	override fun fly()
	override fun quack()
 }
 
class RubberDuck : Duck, Quackable {
	override fun display()
	override fun quack()
 }
 
 class WoodDuck : Duck {
 	override fun display()
 }

문제점: <인터페이스는 모든 서브클래스에서 구현해야하므로 관리가 힘듦
또한 날 수 있는 오리에게는 나는 코드를 복붙해야한다. 즉 코드 재활용이 안된다.

디자인 원칙

  • 애플리케이션의 달라지는 부분을 찾아내고, 달라지지 않는 부분과 분리한다.
    • 달라지는 부분을 추출해 캡슐화한다.
  • 구현보다는 인터페이스에 맞춰서 프로그래밍한다.
  • 상속보다는 구성을 활용한다.
상속(Inheritance) 구성(Composition)
관계 is-a has-a
기능 클래스가 클래스를 확장하여 속성 및 동작을 상속 클래스가 다른 클래스의 객체를 멤버 데이터로 포함
캡슐화 X O

전략(Strategy) 패턴

알고리즘군을 정의하고 캡슐화해서 각각의 알고리즘군을 수정해서 쓸 수 있게 한다.
전략 패턴을 사용하면 클라이언트로부터 알고리즘을 분리해서 독립적으로 변경할 수 있다.

= 행위를 클래스로 캡슐화해 동적으로 행위를 자유롭게 바꿀 수 있게 해주는 패턴


인터페이스와 상위 형식에 맞춰 프로그래밍

image

  1. 인터페이스 선언
type FlyBehavior interface {
	fly()
}
  1. 구체적인 구현 메소드 정의
type FlyWithWings struct{}

type FlyNoWay struct{}

// 실제 구체적인 나는 행동을 구현
func (f FlyWithWings) fly() {
	fmt.Println("날고 있어요!!")
}

func (f FlyNoWay) fly() {
	fmt.Println("저는 못 날아요")
}
  1. 오리 구조체에 할당
type Duck struct {
	Name          string
	FlyBehavior   FlyBehavior
}

func (d *Duck) GetName() {
	fmt.Printf("저는 %s입니다.\n", d.Name)
}

func (d *Duck) PerformFly() {
	d.FlyBehavior.fly()
}
  1. 실행
parkDuck := duck.Duck{
		Name:          "병찬오리",
		FlyBehavior:   duck.FlyNoWay{},
	}
	parkDuck.GetName()
	parkDuck.PerformFly()