japan.internet.com
japan.internet.com メンバーID
Twitter
Facebook
RSS
ピックアップ
2010年2月9日 10:00

C#におけるNull Objectパターン

著者Sajad Deyargaroo海外海外発

はじめに

 Nullオブジェクトとは、オブジェクトが存在しないことを表すオブジェクトです。何の動作も行わずに、デフォルトを返します。Nullオブジェクトは、オブジェクト参照がNullである場合に使われます。Null Objectパターンはクライアントコードを簡素化し、誤りを生じにくくするのに役立ちます。

 例えば、顧客アカウントを確認し、顧客がゴールド会員であるかどうかをチェックする簡単な販売アプリケーションを考えてみましょう。ゴールド会員は、割引や配送料無料など、さまざまな特典を受けることができるものとします。

 以下は、mainメソッドのコードスニペットです。顧客のアカウント情報を取得し、そのゴールド会員プロファイルを取り出し、そのゴールド会員に適用されるすべての特典を適用します。

string userName = args[0];
string pin = args[1];
Order order = new Order();

for (int i = 2; i < args.Length; i++)
{
    order.Amount += Convert.ToDecimal(args[i]);
}

var account = AccountController.GetAccount(userName, pin);

if (account == null)
{
    Console.WriteLine("Invalid Account");
}
else
{
    var gProfile = GoldMembershipController.GetProfile(account);

    if (gProfile != null)
    {
        order.Amount -= gProfile.GetDiscount(order.Amount);
    }

    if (gProfile != null)
    {
        if (!gProfile.IsShippingFree)
        {
            order.Amount += order.GetShippingCharges();
        }
    }
    else
    {
        order.Amount += order.GetShippingCharges();
    }

    Console.WriteLine(string.Format("Total Amount: {0}", order.Amount));
}
 顧客が有効なアカウントを所有する場合、AccountController.GetAccount(userName, pin)Accountオブジェクトを返し、それ以外の場合はnullを返します。同様に、顧客がゴールド会員であれば、GoldMembershipController.GetProfile(account)GoldMembershipオブジェクトを返し、ゴールド会員でない場合はnullを返します。

 上のコードスニペットから分かるように、null参照をチェックする条件文が何度も繰り返し出現します。条件文は通常、条件結果に基づいて分岐するために使用します。上のゴールド会員であるかをチェックする部分では、同じフローの中で、null参照をチェックするためだけに2つの条件文が使用されています。これでは、コードが長くなって理解しにくくなるだけでなく、大きなプログラムではnullのチェックを忘れてしまいがちであるため、非常に誤りが生じやすくなります。Null Objectパターンは、このような問題を解決するためのものです。

 Null Objectパターンを実装すると、GoldMembershipController.GetProfile(accountId)は常にオブジェクトを返すことになります。顧客がゴールド会員ではない場合には、Nullオブジェクトを返します。Null Objectパターンを実装するには、IGoldMembershipインターフェースを作成し、GoldMembershipクラスとNullGoldMembershipクラスの両方でこのインターフェースを実装します。NullGoldMembershipクラスは、何も行わずにデフォルトを返すだけのクラスです。GoldMembershipController.GetProfile(accountId)メソッドも変更し、ユーザーがゴールド会員である場合はGoldMembershipオブジェクト、ゴールド会員でない場合はNullGoldMembershipオブジェクトを返すようにします。

public interface IGoldMembership
    {
        decimal GetDiscount(decimal amount);
        bool IsShippingFree { get; set; }
    }

public class GoldMembership : IGoldMembership
    {
        public GoldMembership(string userName)
        {
            // get gold member profile of this user

            IsShippingFree = true;
        }

        public bool IsShippingFree { get; set; }

        public decimal GetDiscount(decimal amount)
        {
            decimal discount = 100;

            //calculate discount

            return discount;
        }
    }

public class NullGoldMembership : IGoldMembership
    {
        public NullGoldMembership()
        {
            IsShippingFree = false;
        }

        public decimal GetDiscount(decimal amount)
        {
            return 0;
        }

        public bool IsShippingFree { get; set; }
    }

public class GoldMembershipController
    {
        public static IGoldMembership GetProfile(Account account)
        {
            // if this account has gold membership
            // return profile else return null

            if (account.Type == "GoldMember")
            {
                return new GoldMembership(account.UserName);
            }
            else
            {
                return new NullGoldMembership();
            }
        }
    }
 Null Objectパターンを実装した後のmainメソッドのコードは、次のようになります。

string userName = args[0];
string pin = args[1];
Order order = new Order();

for (int i = 2; i < args.Length; i++)
{
    order.Amount += Convert.ToDecimal(args[i]);
}

var account = AccountController.GetAccount(userName, pin);

if (account == null)
{
    Console.WriteLine("Invalid Account");
}
else
{
    var gProfile = GoldMembershipController.GetProfile(account);

    order.Amount -= gProfile.GetDiscount(order.Amount);

  if (!gProfile.IsShippingFree)
  {
          order.Amount += order.GetShippingCharges();
  }

    Console.WriteLine(string.Format("Total Amount: {0}", order.Amount));
}
 Null Objectパターンを実装した後のクライアントサイドのコードは、かなりすっきりしたものになりました。簡潔であるだけでなく、理解しやすいものになっています。

 しかし、Null Objectパターンを使用すればnull参照を完全になくすことができるわけではありません。オブジェクトが存在するか否かによって分岐しなければならない場合もあり、そのような場合にはやはりnull参照を使用する必要があります。例えば、ユーザーが有効なアカウントを所有しない場合は、その後の処理は行わず、単にエラーメッセージを表示します。このような場合には、次のようにnull参照を使用し、チェックする必要があります。

var account = AccountController.GetAccount(userName, pin);

if (account == null)
{
    Console.WriteLine("Invalid Account");
}
else
{
    // process the transaction
}
 それでは、ハッピーコーディング!

著者紹介

Sajad Deyargaroo(Sajad Deyargaroo)
MCTS、MCP資格を取得。VB 4.0とC++のアプリケーション開発からこの世界に入る。プログラミングへの関心は数多くの言語にわたるが、現在は.Netに没頭している。最近は、AISとともにMicrosoftの技術に取り組んでおり、複数の雑誌およびWeb上に多くの記事を執筆している。電子メールアドレスはsajad@programmer.net。

関連テーマ
プリンター用
記事を転送
この記事をクリップ!
【特別連載企画】大艦巨砲主義にして卓越したレスポンス--GALAXY S II WiMAX
【特別連載企画】大艦巨砲主義にして卓越したレスポンス--GALAXY S II WiMAX 1月20日より販売が開始されたサムスン製スマートフォン「GALAXY S II WiMAX」。カタログスペックでは、他メーカーのハイエンド機と同じように見えても、実際に使うと卓越したレスポンスに驚かされる。
⇒詳細記事はこちら
⇒連載記事一覧はこちら
注目のトピックス
最新コラム一覧
百式のネットビジネス研究
百式のネットビジネス研究
次のフライトでお好みの座席が空いたら教えてくれる「Expert Flyer」
週刊-サイト別アクセス状況データ
週刊-サイト別アクセス状況データ
12月の主婦層、ベルメゾンが首位を維持(VRI 調査)
アウンのグローバルマーケティング動向
アウンのグローバルマーケティング動向
Web プロモーションにおいて大切なこと―年度末編―
多言語×Web×海外マーケティング情報
多言語×Web×海外マーケティング情報
海外発、注目 AR プロモーション
エンジニア転職ノウハウ開発室
エンジニア転職ノウハウ開発室
楽天が目指す変革──Globalization、Agile、Big Data
中国・台湾ネットビジネス情報最前線
中国・台湾ネットビジネス情報最前線
中国から Web を見てもらいたいならば
マーケティングに活用できる最新トレンド
マーケティングに活用できる最新トレンド
改めて、「導線」最適化に目を向ける
次世代マーケティングチェーンの視点
次世代マーケティングチェーンの視点
ソーシャル時代における BtoC 型 Eコマース成功のポイント
Copyright 2012 internet.com K.K. (Japan) All Rights Reserved.