作成日 2007/8/12
最終更新日 2014/6/8
[ Japanese | English ]

インスタンススコープの属性とクラススコープの属性

 UML(※1)のクラス図では、クラスの属性はいろいろな点から分類することが出来るのですが、データの持ち方と言う点から分類する(※2)と、2つに分けることが出来ます。
 1つがインスタンススコープの属性で、もう一つがクラススコープの属性です。

 このページではインスタンススコープの属性とクラススコープの属性の特徴、違いを説明し、どのような箇所で使用されているか(※3)を説明します。

※1:UMLのバージョンは2.0とします。
※2:他にも、可視性(public,private,protected,package)、読み取り専用かどうか、派生属性(他の属性や関連から導き出せるものか?)かどうか、などから分類可能です。
UML2.0の仕様ではクラスの属性はClassクラス(※メタクラスです)からPropertyクラス(※メタクラスです)への関連として定義してあるので(UML2.0の仕様書 p29 Figure 7.12)、結局 、クラスの属性を分類するというのは、PropertyクラスやPropertyクラスの親クラス(StructualFeatureクラス(※抽象メタクラスです)やFeatureクラス(※抽象メタクラスです))の属性や関連を調べるのと同じ気がします。
※3:クラススコープの属性のみとします。というのは、インスタンススコープの属性は使用頻度が高いので、改めて説明する必要は無いと思ったためです。

1.インスタンススコープの属性とは
2.クラススコープの属性とは
3.クラススコープの属性の使用例
4.サンプルソース
5.参考文献など


1.インスタンススコープの属性とは

 とりあえず、図1のクラス図を見てください。
インスタンススコープの属性とクラススコープの属性の例
図1 クラス図

 クラス図で下線が引かれていない属性が、インスタンススコープの属性となります。
 インスタンススコープの属性はインスタンスごとに違った値(同じ値となることもある)を持ちます。…と、このような説明だと難しくてわからないので、「クラスとオブジェクト 3.具体例1(電話帳の例)」の図1と図2を見てください。
 図1を見ると、「名前」属性や「電話番号」属性は1行1行、違った値を持っています(1行ごとに別の値を持つことが出来る)。このような属性はインスタンススコープの属性です(※1)。

※1:インスタンススコープの属性と、クラススコープの属性を対比して書かないとわかりずらいか…。
とりえあえず、クラススコープの属性についての説明も読んで欲しいです。
このページのトップへ

2.クラススコープの属性とは

 これもまた、とりあえず、図2のクラス図(図1と同じ図です)を見てください。

インスタンススコープの属性とクラススコープの属性の例
図2 クラス図(※1)
 
 クラス図で下線が引かれている属性が、クラススコープの属性となります(※2)。
 とりあえず、図3を見てください。

電話帳データの例
図3 電話番号のデータとデータ数(※1)

 クラススコープの属性はクラスのインスタンスごとに違った値を持つのではなく、クラスで1つの値を持ちます。
 図2の例ではデータ数(電話帳クラスのインスタンスの数)は個々のインスタンスが持つデータではありません。 

※1:ここでは、インスタンスのデータ数をクラススコープの属性として定義しました。しかし、これは例としてあげたのであって、実際の設計において、インスタンスのデータ数を常にクラススコープの属性として持たせるとは限りません。クラススコープの属性としてしまうと、確かにクラスのインスタンスの数を管理できますが、実際には1年1組の児童の電話帳データ数、1年2組の児童の電話帳データ数のように、何かでグループ分けした中でのデータ数は管理することが出来ません。
エクセルVBAでもインスタンスの数をクラススコープの属性として持っている例は恐らく無く、多くの場合はそのクラスのコレクションクラスが持っています(Countプロパティでインスタンスの数を取得する)。例えば、ExcelライブラリのWorksheetクラスのオブジェクトはWorksheetsクラス(※コレクションクラスです)が持ちます。(ちなみにWorkSheetsオブジェクトはWorkbookクラスが管理しています。結局、Worksheetクラスのオブジェクト(エクセルのワークシート)はWorkbookクラスのオブジェクト(エクセルファイルと考えてよい)ごとで管理する必要があるので、Worksheetクラスのオブジェクトの数も(直接的にではないにせよ)Workbookクラスのオブジェクトが管理する必要があるため、このようなデータ数をクラススコープの属性で保持するのではなく、コレクションクラスのインスタンススコープの属性で保持するようにしていると思います。)
※2:クラススコープの属性や操作に対して、下線を引くというのは、UML2.0の仕様書では、7.3.19 Feature(from Kernel)のNotationのところ(p67)に書いてある気がします。英語なのでよくわかりませんが…。
Featureクラス(※抽象メタクラスです)はOperationクラス(※メタクラスです)やPropertyクラス(※メタクラスです)の親クラスの親クラスです。 
このページのトップへ

3.クラススコープの属性の使用例

 クラススコープの属性が使用される例としては、まずは、GoFのデザインパターンの一つであるシングルトンパターンでしょうか。
 シングルトンパターンとは、クラスのインスタンスが1つとなることを保障したいときに使用するデザインパターンです。
 それ以外のデザインパターンで、クラススコープの属性を使用するものは、だるまは知らないです。ただ、デザインパターンの中には、他のデザインパターンと組み合わせて使用されるものがあるので、シングルトンパターンと組み合わせて使用されるデザインパターンも見ておくと良いかもしれません(※1)。

 他に、良くある例としては、システムで共通に使用する定数をファイルに書き込んでおき、システムの起動直後にクラススコープの属性値にセットする(※2)ことがあります。

 他には…、思い浮かばないです。

※1:例えば、フライウェイトパターン。他は…、知らない。
※2:ファイルから読み込むのではなく、RDB(リレーショナルデータベース)から読み込んだり、どこかのリソースから読まずにプログラムに直接、値を書いてしまう方法もあります。
このページのトップへ

4.サンプルソース

 クラス図だけじゃ、理解できん!というお叱りを受けたので、ソース(実装例)も出します。言語はJavaC++VBAです。

■Javaの場合(動作確認環境:JRE1.6)

電話帳クラス(ファイル名:TelephoneBook.java)
/** 電話帳クラス。1件分のデータを保持します。 */
public class TelephoneBook {
    /** 名前 */
    private String name;
    /** 電話番号 */
    private String number;
    /** データ数 */
    private static int dataCount = 0;
    /***
     * コンストラクタ
     */
    public TelephoneBook(){
        dataCount++;
    }
    /**
     * 名前を返します。
     * @return 名前
     */
    public String getName() {
        return name;
    }
    /**
     * 名前を設定します。
     * @param name 設定する名前
     */
    public void setName(String name) {
        this.name = name;
    }
    /**
     * 電話番号を返します。
     * @return 電話番号
     */
    public String getNumber() {
        return number;
    }
    /**
     * 電話番号を設定します。
     * @param number 設定する電話番号
     */
    public void setNumber(String number) {
        this.number = number;
    }
    /**
     * データ数を返します。
     * @return データ数
     */
    public static int getDataCount() {
        return dataCount;
    }
}
※このソースだと、データ数が増えるだけで、減ることがありません。本来は不具合なのですが、これはサンプルなので許してください。


電話帳オブジェクトを生成して表示してみるサンプル(ファイル名:Main.java)
import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        // オブジェクト作成
        ArrayList<TelephoneBook> teleBook = new ArrayList<TelephoneBook>();

        TelephoneBook obj = null;

        obj = new TelephoneBook();
        obj.setName("山田 太郎");
        obj.setNumber("01-2345-6789");
        teleBook.add(obj);

        System.out.println("データ数:" + TelephoneBook.getDataCount());

        obj = new TelephoneBook();
        obj.setName("上野 花子");
        obj.setNumber("03-0303-9999");
        teleBook.add(obj);

        System.out.println("データ数:" + TelephoneBook.getDataCount());

        obj = new TelephoneBook();
        obj.setName("だるま 太郎");
        obj.setNumber("04-000-1234");
        teleBook.add(obj);

        System.out.println("データ数:" + TelephoneBook.getDataCount());
    }
}


実行結果(標準出力)
データ数:1
データ数:2
データ数:3

■C++の場合(動作確認環境:OS:Windows 7 , コンパイラ:VC++ 2010のcl.exe )

電話帳クラスの定義(ファイル名:TelephoneBook.h)
/**
 * @file
 */

#ifndef TELEPHONEBOOK_H_
#define TELEPHONEBOOK_H_

#include <string>

/// @brief 電話帳クラス。1件分のデータを保持します。
class TelephoneBook {
private:
    std::string name;    ///< @brief 名前
    std::string number;  ///< @brief 電話番号
    static int dataCount;///< @brief データ数
public:
    /// @brief コンストラクタ
    TelephoneBook();
    /// @brief コピーコンストラクタ
    TelephoneBook(const TelephoneBook& other);
    /// @brief デストラクタ
    virtual ~TelephoneBook();

    /// @brief 名前を返します。 @return 名前
    std::string getName() const;
    /// @brief 名前を設定します。 @param[in] name 設定する名前
    void setName(const std::string& name);
    /// @brief 電話番号を返します。 @return 電話番号
    std::string getNumber() const;
    /// @brief 名前を電話番号します。 @param[in] name 設定する電話番号
    void setNumber(const std::string& number);
    /// @brief データ数を返します。 @return データ数
    static int getDataCount();
};

#endif /* TELEPHONEBOOK_H_ */


電話帳クラスの関数の定義(ファイル名:TelephoneBook.cpp)
#include "TelephoneBook.h"

using namespace std;

int TelephoneBook::dataCount = 0;

TelephoneBook::TelephoneBook() {
    dataCount++;
}

TelephoneBook::TelephoneBook(const TelephoneBook& other) {
    dataCount++;
    *this = other;
}

TelephoneBook::~TelephoneBook() {
    dataCount--;
}

string TelephoneBook::getName() const {
    return name;
}

void TelephoneBook::setName(const string& name) {
    this->name = name;
}

string TelephoneBook::getNumber() const {
    return number;
}

void TelephoneBook::setNumber(const string& number) {
    this->number = number;
}

int TelephoneBook::getDataCount() {
    return dataCount;
}
※上記の場合、関数定義をヘッダーファイルで行い、インライン関数にした方が効率が良さそうですが、今回はそういうことはしていません。

電話帳オブジェクトを生成して表示してみるサンプル(ファイル名:Main.cpp)
#include <iostream>
#include <string>
#include <vector>
#include "TelephoneBook.h"

using namespace std;

int main() {
    vector<TelephoneBook> teleBook;

    TelephoneBook obj;

    cout << "データ数:" << TelephoneBook::getDataCount() << endl;

    obj.setName("山田 太郎");
    obj.setNumber("01-2345-6789");
    teleBook.push_back(obj);

    cout << "データ数:" << TelephoneBook::getDataCount() << endl;

    obj.setName("上野 花子");
    obj.setNumber("03-0303-9999");
    teleBook.push_back(obj);

    cout << "データ数:" << TelephoneBook::getDataCount() << endl;

    obj.setName("だるま 太郎");
    obj.setNumber("04-000-1234");
    teleBook.push_back(obj);

    cout << "データ数:" << TelephoneBook::getDataCount() << endl;
    return 0;
}
※注意:C++のstd::vectorのpush_back関数は、オブジェクトへの参照を配列に追加するのではなく、実体をコピーします。
なので、push_backするたびに、データ数が増えます。


実行結果(標準出力)
データ数:1
データ数:2
データ数:3
データ数:4

■VBAの場合(動作確認環境:VBA 6.0 )

電話帳クラス(モジュール名:TelephoneBook(クラスモジュール))
''
' 電話帳クラス。クラススコープの属性と操作を定義します。
Option Explicit

'' データ数
Private m_dataCount As Integer

''
' データ数を返します。
' @return データ数
Public Property Get dataCount() As Integer
    dataCount = m_dataCount
End Property

''
' データ数を1増やします
Public Sub addDataCount()
    m_dataCount = m_dataCount + 1
End Sub

''
' データ数を1減らします
Public Sub removeDataCount()
    m_dataCount = m_dataCount - 1
End Sub
※VBAではクラスモジュール内に定義した属性や関数はすべてインスタンススコープの属性・関数になります。
クラススコープの属性や関数は定義できません。なので、標準モジュールに定義することになります。

電話帳クラス(モジュール名:TelephoneBook(クラスモジュール))
''
' 電話帳クラス。1件分のデータを保持します。
Option Explicit

'' 名前
Private m_name As String
'' 電話番号
Private m_number As String

''
' オブジェクト生成時に呼び出されます。
Private Sub Class_Initialize()
    Call stTelephoneBook.addDataCount
End Sub

''
' オブジェクト解放時に呼び出されます。
Private Sub Class_Terminate()
    Call stTelephoneBook.removeDataCount
End Sub

''
' 名前を返します。
' @return 名前
Public Property Get name() As String
    name = m_name
End Property

''
' 名前を設定します。
' @param newName 設定する名前
Public Property Let name(ByVal newName As String)
    m_name = newName
End Property

''
' 電話番号を返します。
' @return 電話番号
Public Property Get number() As String
    number = m_number
End Property

''
' 電話番号を設定します。
' @param newNumber 設定する電話番号
Public Property Let number(ByVal newNumber As String)
    m_number = newNumber
End Property


電話帳オブジェクトを生成して表示してみるサンプル(ファイル名:Main(標準モジュール))
Option Explicit

Sub main()
    Dim teleBook As New Collection
    Dim i As Integer

    Dim obj As TelephoneBook

    Set obj = New TelephoneBook
    obj.name = "山田 太郎"
    obj.number = "01-2345-6789"
    Call teleBook.Add(obj)
    
    Debug.Print "データ数:" & stTelephoneBook.dataCount
    
    Set obj = New TelephoneBook
    obj.name = "上野 花子"
    obj.number = "03-0303-9999"
    Call teleBook.Add(obj)
    
    Debug.Print "データ数:" & stTelephoneBook.dataCount

    Set obj = New TelephoneBook
    obj.name = "だるま 太郎"
    obj.number = "04-000-1234"
    Call teleBook.Add(obj)
    
    Debug.Print "データ数:" & stTelephoneBook.dataCount
End Sub


実行結果(イミディエイトウィンドウ)
データ数:1
データ数:2
データ数:3
このページのトップへ

5.参考文献など

 このページを作成するのに参考にしたページです。
 ただし、だるまは、このページを作成するにあたり、これらのページを100%理解してから作成したわけではない(おいおい。)です。
 間違い(リンク先のページではなく、このページに)があったら、ごめんなさい。

番号

リンク先の名称

リンク先の説明

リンクした日

1 OMG Document -- UML 2.0の仕様書(UML Superstructure Specification, v2.0)がダウンロードできます。(※英語のページです) 2007/6/24
2 Singleton パターン - Wikipedia GoFのデザインパターンの1つであるシングルトンパターンについて説明があります。 2007/8/13
3 Flyweight パターン - Wikipedia GoFのデザインパターンの1つであるフライウェイトパターンについて説明があります。 2007/8/14

番号

著者名

書籍名

ISBN

1 オージス総研オブジェクトの広場編集部、山内 亨和 その場でつかえるしっかり学べるUML2.0 978-4798012391
2 結城 浩 増補改訂版Java言語で学ぶデザインパターン入門 978-4797327038

 
Prev Up Next  Top
このページのトップへ

このページの利用によって発生した、いかなる損害について、このホームページの作成者は責任を負いません。
このページの間違いや嘘を見つけた方、このページに書いて欲しい情報がある方はメールをお願いします。

Microsoft 、Windows 、Visual Basic および Excel は米国Microsoft Corporationの米国およびその他の国における登録商標または商標です。
ここではExcel® をエクセル、Visual Basic® for Applications をVBAと表記する場合があります。
Mac 、Mac OS 、Mac OS X は米国Apple Computer,Inc.の登録商標または商標です。
OMG、UML、Unified Modeling Languageは、Object Management Groupの商標または登録商標です。
その他、社名および商品名、システム名称などは、一般に各社の商標または登録商標です。

このホームページの作成者はこれらの会社とはいっさい関係がありません。