C#入門(第14回)

前回振り返り

Decoratorパターン

Decoratorパターンでは、オブジェクトに付加的な責務(機能や振る舞い)を動的に加えることができます。

このパターンでは、既存のオブジェクトを新しい Decorator オブジェクトでラップし、機能を拡張する。実装としては、Decorator のコンストラクタの引数でラップ対象の Component オブジェクトを読み込み、コンストラクタの内部でそのオブジェクトをメンバに設定することが一般的である。

Decoratorパターンのクラス図

前回演習問題の解答 例

問題1

問題文

Decoratorパターン を作成してみましょう。

wikipedia のJava実装例をC#で記述してみましょう。


解答例

Console.WriteLine(
    new WholesalePrice(
        new DoublePrice(
            new WholesalePrice(
                new DoublePrice(
                    new PrimePrice(120)
                    )
                , 80
                )
            )
        , 200
        )
    .getValue()
    );
public interface Price
{
    int getValue();
}
public class PrimePrice : Price
{
    private int value;
    public PrimePrice(int value)
    {
        this.value = value;
    }
    public int getValue()
    {
        return this.value;
    }
}
using System.Diagnostics;

public abstract class MarginPrice : Price
{
    protected Price originalPrice;
    public MarginPrice(Price price){
        this.originalPrice = price;
    }
    public abstract int getValue();
}
public class WholesalePrice : MarginPrice
{
    private int advantage;
    public WholesalePrice(Price price, int advantage) : base(price)
    {
        this.advantage = advantage;
    }
    public override int getValue()
    {
        return this.originalPrice.getValue() + advantage;
    }
}
public class DoublePrice : MarginPrice
{

    public DoublePrice(Price price) : base(price)
    {        
    }
    public override int getValue()
    {
        return this.originalPrice.getValue() * 2;
    }
}

問題2

問題文

問1のクラスを身近なものにアレンジしてみましょう。


解答例

public class DecoratorTest
{
    public static void Main(String[] argv)
    {
        Item soap = new PrimePriceItem("石鹸", 100);
        Item banana = new PrimePriceItem("バナナ", 100);

        soap.print();
        banana.print();
        new DailyUseWithTaxDecorator(soap).print();
        new FoodWithTaxDecorator(banana).print();

        new DailyUseWithTaxDecorator(new TenPercentPriceIncreaseDecorator(soap)).print();
        new FoodWithTaxDecorator(new TenPercentPriceIncreaseDecorator(banana)).print();

        new DailyUseWithTaxDecorator(new TenPercentPriceIncreaseDecorator(new TenPercentPriceIncreaseDecorator(soap))).print();
        new FoodWithTaxDecorator(new TenPercentPriceIncreaseDecorator(new TenPercentPriceIncreaseDecorator(banana))).print();


    }
}
abstract class Item
{
    public abstract String getName();
    public abstract int getPrice();
    public void print()
    {
        Console.WriteLine(getName() + ":" + getPrice() + "円");
    }
}

/** 原価の品目を表すクラス */
class PrimePriceItem : Item
{
    private String name;
    private int price;
    public PrimePriceItem(String name, int price)
    {
        this.name = name;
        this.price = price;
    }
    public override String getName()
    {
        return this.name;
    }
    public override int getPrice()
    {
        return this.price;
    }
}

/** Decoratorクラス */
abstract class Decorator : Item
{
    protected Item originalItem;
    protected Decorator(Item item)
    {
        this.originalItem = item;
    }
}

/** 日用品に消費税を付与するクラス */
class DailyUseWithTaxDecorator : Decorator
{
    public DailyUseWithTaxDecorator(Item item) : base(item)
    {
    }
    public override String getName()
    {
        return this.originalItem.getName() + "(税込)";
    }
    public override int getPrice()
    {
        if (this.originalItem is DailyUseWithTaxDecorator)
        {
            throw new NotSupportedException("多重課税です");
        }
        return (int)(this.originalItem.getPrice() * 1.1f);
    }
}

/** 食品に消費税を付与するクラス */
class FoodWithTaxDecorator : Decorator
{
    public FoodWithTaxDecorator(Item item) : base(item)
    {
    }
    public override String getName()
    {
        return this.originalItem.getName() + "(税込)";
    }
    public override int getPrice()
    {
        if (this.originalItem is FoodWithTaxDecorator)
        {
            throw new NotSupportedException("多重課税です");
        }
        return (int)(this.originalItem.getPrice() * 1.08f);
    }
}

/** 10%値上げするクラス */
class TenPercentPriceIncreaseDecorator : Decorator
{
    public TenPercentPriceIncreaseDecorator(Item item) : base(item)
    {
    }
    public override String getName()
    {
        return this.originalItem.getName() + "(" + this.originalItem.getPrice() + "→" + this.getPrice() + "円に改定)";
    }
    public override int getPrice()
    {
        return (int)(this.originalItem.getPrice() * 1.1f);
    }
}

今回の演習問題

問題1

問題文

Facadeパターン を作成してみましょう。

wikipedia のJava実装例をC#で記述してみましょう。

問題2

問題文

問1のDrivingSimulator#simulateでは、pushPedalメソッドの引数に分速を渡しているが、時速に変更するとどうなるでしょうか。

コメント