0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

最小限で理解するDecoratorパターン

0
Last updated at Posted at 2024-05-26

はじめに

デコレーターパターンを調べていると、抽象クラスが登場し必要以上に複雑化していると感じました。
ここではデコレーターパターンの本質を最小限のサンプルコードを用いて解説したいと思います。

デコレーターパターンとは

  • デコレーター...装飾者
  • 装飾対象オブジェクトを飾り枠で装飾することによって機能の拡張ができる
  • 飾り枠と装飾対象を同一視する(同じインターフェースまたは抽象クラスを実装・継承する)ことによって、クライアントは違いを意識することなく使える
  • デコレーターの実装クラスは、装飾対象のインスタンスをフィールドにもつ

メリット

  • 既存のオブジェクトに変更を加えず、機能を動的に追加できる
  • デコレーターを組み合わせて多様な機能を実現できる
  • 責務を分離できる

デメリット

  • デコレーターが多重の場合、処理の順序を理解するにコストがかかる
  • デコレーターによっては順序に依存するものがあり、適切な順序を考慮する必要がある

シンプルな例を試してみる

  • お題:プレーンテキストを様々なHTMLタグで装飾してみる
  • 登場人物
    • Text.ts...装飾される対象のインターフェース
    • PlainText.ts...Textインターフェースの実装。装飾対象オブジェクト
    • BoldDecorator.ts...bタグ(太字)で装飾する。装飾対象をフィールドにもつ
    • ItalicDecorator.ts...iタグ(斜体)で装飾する。装飾対象をフィールドにもつ

クラス図

image.png

main.ts
import { Text } from "./Text";
import { PlainText } from "./PlainText";
import { BoldDecorator } from "./Decorators/BoldDecorator";
import { ItalicDecorator } from './Decorators/ItalicDecorator'

let text: Text = new PlainText("Hello, World!");
console.log("デコレーターなし: " + text.format());
text = new BoldDecorator(text);
console.log('Boldのみ: ' + text.format());
text = new ItalicDecorator(text);
console.log('Italic + Bold: ' + text.format());
Text.ts
export interface Text {
    format(): string;
}
PlainText.ts
import {Text} from "./Text";

export class PlainText implements Text {
    private text: string;
    
    constructor (text: string) {
        this.text = text;
    }

    public format(): string{
        return this.text;
    }
}
Decorators/BoldDecorator.ts
import { Text } from "../Text";

export class BoldDecorator implements Text {
    private component: Text;
    
    constructor(component: Text){
        this.component = component;
    }
    
    public format(): string {
        return `<b>${this.component.format()}</b>`
    }
}
Decorators/ItalicDecorator.ts
import { Text } from "../Text";

export class ItalicDecorator implements Text {
    private component: Text;
    
    constructor(component: Text){
        this.component = component;
    }
    
    public format(): string{
        return `<i>${this.component.format()}</i>`
    }
}

実行結果:

image.png

おわりに

もはや雑なメモになってしまいましたが、個人的に以下のポイントを押さえておくと理解しやすいと感じました。

  • デコレーターの実装クラスは装飾対象をフィールドにもつ
  • デコレーターと装飾対象は同じインターフェースまたは抽象クラスを実装・継承する
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?