Chain of Responsibility

godo·2022년 8월 18일
0

Swift - Design Patterns

목록 보기
12/24

Method Chain

class Creature : CustomStringConvertible
{
    var name : String
    var attack : Int
    var defense : Int
    
    init(name: String, attack: Int, defense: Int)
    {
        self.name = name
        self.attack = attack
        self.defense = defense
    }
    
    
    var description: String
    {
        return "Name: \(name), Attack = \(attack), Defense = \(defense)"
    }
}

class CreatureModifier
{
    let creature : Creature
    var next : CreatureModifier?
    
    init(creature : Creature)
    {
        self.creature = creature
    }
    
    func add(_ cm: CreatureModifier)
    {
        if next != nil
        {
            next!.add(cm)
        }
        else
        {
            next = cm
        }
    }
    
    func handle()
    {
        next?.handle() // handle
    }
    
}


class DoubleAttackModifier : CreatureModifier
{
    override func handle()
    {
        print("Doubling \(creature.name)'s attack")
        creature.attack *= 2
        super.handle()
    }
}

class IncreaseDefenseModifier : CreatureModifier
{
    override func handle()
    {
        print("Increasing \(creature.name)'s defense")
        creature.defense += 3
        super.handle()
    }
}

// can cancell 
class NoBonusesModifier : CreatureModifier
{
    override func handle()
    {
        // nothing
        
    }
}


func main()
{
    let Bear = Creature(name: "Bear", attack: 2, defense: 2)
    print(Bear)
    
    let root = CreatureModifier(creature: Bear)
    
//    root.add(NoBonusesModifier(creature: Bear))
    
    print("Let's double the bear's attack")
    root.add(DoubleAttackModifier(creature: Bear))
    
    print("Let's increase bear's defense")
    root.add(IncreaseDefenseModifier(creature: Bear))
    
    root.handle()
    print(Bear)
}

Broker Chain

protocol Invocable : class
{
  func invoke(_ data: Any)
}

public protocol Disposable
{
  func dispose()
}

public class Event<T>
{
  public typealias EventHandler = (T) -> ()

  var eventHandlers = [Invocable]()

  public func raise(_ data: T)
  {
    for handler in self.eventHandlers
    {
      handler.invoke(data)
    }
  }

  public func addHandler<U: AnyObject>
    (target: U, handler: @escaping (U) -> EventHandler) -> Disposable
  {
    let subscription = Subscription(target: target, handler: handler, event: self)
    eventHandlers.append(subscription)
    return subscription
  }
}

class Subscription<T: AnyObject, U> : Invocable, Disposable
{
  weak var target: T?
  let handler: (T) -> (U) -> ()
  let event: Event<U>

  init(target: T?, handler: @escaping (T) -> (U) -> (), event: Event<U>)
  {
    self.target = target
    self.handler = handler
    self.event = event
  }

  func invoke(_ data: Any) {
    if let t = target {
      handler(t)(data as! U)
    }
  }

  func dispose()
  {
    event.eventHandlers = event.eventHandlers.filter { $0 as AnyObject? !== self }
  }
}


// CQS

class Query
{
    var creatureName : String
    enum Argument
    {
        case attack
        case defense
    }
    
    var whatToQuery: Argument
    var value : Int
    
    init(_ name: String, _ whatToQuery: Argument, _ value: Int)
    {
        self.creatureName = name
        self.whatToQuery = whatToQuery
        self.value = value
    }
}


class Game
{
    let queries = Event<Query>()
    
    func performQuery(_ q: Query)
    {
        queries.raise(q)
    }
}

class Creature: CustomStringConvertible
{
    var name: String
    private let _attack, _defense: Int
    private let game: Game
    
    init(_ game: Game, _ name: String, _ attack: Int, _ defense: Int)
    {
        self.game = game
        self.name = name
        _attack = attack
        _defense = defense
    }
    
    var attack: Int
    {
        let q = Query(name, .attack, _attack)
        game.performQuery(q)
        return q.value
    }
    
    var defense: Int
    {
        let q = Query(name, .defense, _defense)
        game.performQuery(q)
        return q.value
    }
    
    var description: String
    {
        return "Name: \(name), Attack = \(attack), Defense = \(defense)"
    }
}


class CreatureModifier : Disposable
{
    let game: Game
    let creature : Creature
    var event: Disposable? = nil
    
    init(_ game: Game, _ creature: Creature)
    {
        self.game = game
        self.creature = creature
        event = self.game.queries.addHandler(target: self, handler: CreatureModifier.handle)
    }
    
    func handle(_ q: Query)
    {
        
    }
    
    func dispose()
    {
        event?.dispose()
    }
}


class DoubleAttackModifier: CreatureModifier
{
    override func handle(_ q: Query)
    {
        if q.creatureName == creature.name && q.whatToQuery == .attack
        {
            q.value *= 2
        }
    }
}


class IncreaseDefenseModifier: CreatureModifier
{
    override func handle(_ q: Query)
    {
        if q.creatureName == creature.name && q.whatToQuery == .defense
        {
            q.value += 2
        }
    }
}


func main()
{
    let game = Game()
    let bear = Creature(game, "Bear", 3, 5)
    print("Baseline : \(bear)")
    
    let dam = DoubleAttackModifier(game, bear)
    print("Bear with double attack : \(bear)")
    
    let idm = IncreaseDefenseModifier(game,bear)
    print("Bear with increase defense : \(bear)")
    
    idm.dispose()
    print("Bear is now \(bear)")
    
    dam.dispose()
    print("Bear is now \(bear)")
}

profile
☀️☀️☀️

0개의 댓글