LoginSignup
1
1

More than 3 years have passed since last update.

Swiftでデザインパターン【Decorator】

Last updated at Posted at 2020-10-15

元ネタ → ochococo/Design-Patterns-In-Swift

クラス図

image.png

図の引用元:Wikipedia: Decorator パターン

概要

The decorator pattern is used to extend or alter the functionality of objects at run- time by wrapping them in an object of a decorator class. This provides a flexible alternative to using inheritance to modify behavior.
Decoratorパターンは、Decoratorクラスのオブジェクトでオブジェクトをラップすることにより、実行時にオブジェクトの機能を拡張または変更するために使用する。継承を使用して動作を変更する代わりに柔軟な方法を提供する。

サンプルコード

// Component
protocol CostHaving {
    // operation
    var cost: Double { get }
}

// Component
protocol IngredientsHaving {
    // operation
    var ingredients: [String] { get }
}

// Component
typealias BeverageDataHaving = CostHaving & IngredientsHaving

// ConcreteComponent
struct SimpleCoffee: BeverageDataHaving {
    // operation
    let cost: Double = 1.0
    let ingredients = ["Water", "Coffee"]
}

// Decorator
protocol BeverageHaving: BeverageDataHaving {
    // component
    var beverage: BeverageDataHaving { get }
}

// ConcreteDecorator
struct Milk: BeverageHaving {
    // component
    let beverage: BeverageDataHaving
    // operation
    var cost: Double {
        return beverage.cost + 0.5
    }
    // operation
    var ingredients: [String] {
        return beverage.ingredients + ["Milk"]
    }
}

// ConcreteDecorator
struct WhipCoffee: BeverageHaving {
    // component
    let beverage: BeverageDataHaving
    // operation
    var cost: Double {
        return beverage.cost + 0.5
    }
    // operation
    var ingredients: [String] {
        return beverage.ingredients + ["Whip"]
    }
}


// usage //
// 型推論に任せずに明示的に型を決定している。これによって、MilkもWhipCoffeeも同等に扱えるようにしている。
var someCoffee: BeverageDataHaving = SimpleCoffee()
print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)")
someCoffee = Milk(beverage: someCoffee)
print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)")
someCoffee = WhipCoffee(beverage: someCoffee)
print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)")

クラス図との対応

サンプルコード クラス図
CostHaving Component
cost operation
サンプルコード クラス図
IngredientsHaving Component
ingredients operation
サンプルコード クラス図
BeverageDataHaving Component
サンプルコード クラス図
SimpleCoffee ConcreteComponent
cost, ingredients operation
サンプルコード クラス図
BeverageHaving Decorator
beverage Component
サンプルコード クラス図
Milk, WhipCoffee ConcreteDecorator
beverage component
cost, ingredients operation

考察

SimpleCoffeConcreteComponent)とMilk/WhipCoffeConcreteDecorator)に対して同じプロトコルBeverageDataHavingComponent)に準拠させ、cost/indredientsoperation)という同一メソッドの実行時の振る舞いを変えている(ポリモーフィズム)。
someCoffeeは、はじめはSimpleCoffeeのイニシャライザで生成され、その後、MilkWhipCoffeeのイニシャライザで置き換えられているが、BeverageDataHaving型としてアップキャストされているので、すべて同じ型として扱うことができる。
また、MilkWhipCoffeeともにbeverageを持つことで(集約)、デフォルトの値を参照している。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1