- PR -

特定のメソッドの等の呼び出しを強制させる方法

投稿者投稿内容
Forte
会議室デビュー日: 2007/07/24
投稿数: 19
投稿日時: 2008-08-01 18:29
とあるクラスのとあるメソッドの呼び出しを強制させる方法はないでしょうか?

たとえば…

コード:
Class BaseClass
	Sub New(ByVal iArg As Integer)
	End Sub
End Class

Class SubClass
	Inherits BaseClass
	Sub New()
		MyBase.New(0)
	End Sub
End Class



上記のコードでは、子クラスのコンストラクタで親クラスのNewを強制されます。

同じような要領で、
「コンストラクタ内で」「○○を呼び出さないと」コンパイルエラー
「(IDisposableを継承させて)Dispose内で」「○○を呼び出さないと」コンパイルエラー
といった、メソッドの呼び出しを強制させる方法は無いでしょうか?


都合により、自クラスのコンストラクタ内では実行出来ないが、
使用する際は必ず呼んでおいて欲しい処理があるとき、
呼び出しを忘れないようにさせたい事が目的です。


開発環境:WindowXP SP-2
開発言語:VB.net
開発ツール:VisualStudio2005
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2008-08-01 22:46
呼び出しを忘れたときに例外をスローするようにしておきます。
よこけん
大ベテラン
会議室デビュー日: 2006/01/31
投稿数: 216
投稿日時: 2008-08-01 23:26
派生クラスの実装の話でしたら、テンプレートメソッドパターンや、ハリウッド原則について勉強すると良いと思います。
_________________
C#と諸々
Forte
会議室デビュー日: 2007/07/24
投稿数: 19
投稿日時: 2008-08-06 00:26
Jittaさん、よこけんさん、お返事ありがとうございます。
返答が遅くなってすみません。。

引用:

呼び出しを忘れたときに例外をスローするようにしておきます。


実行時にお知らせだと、希にしか呼び出されないコードにバグを潜ませてしまいそうなので…
出来ればコンパイル時に知りたいです。



引用:

派生クラスの実装の話でしたら、テンプレートメソッドパターンや、ハリウッド原則について勉強すると良いと思います。


ハリウッド原則について、少し調べてみました。
必要な処理は必要になったら、フレームワーク側が呼ぶから、使う側は意識しなくていい、という設計思想でしょうか。

もう少し勉強してみます。

Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2008-08-06 14:50
なにをしたいのか、よくわからないのですが。。。

デフォルトのコンストラクタをプライベートにして、コンストラクタと必要なメソッドを実行するスタティックなメソッドを用意するとか。

Dispose は、親クラスの Dispose メソッドが必要な処理を行い、回りにさせるべきではないでしょう。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2008-08-06 16:19
引用:

Forteさんの書き込み (2008-08-01 18:29) より:
上記のコードでは、子クラスのコンストラクタで親クラスのNewを強制されます。

同じような要領で、
「コンストラクタ内で」「○○を呼び出さないと」コンパイルエラー
「(IDisposableを継承させて)Dispose内で」「○○を呼び出さないと」コンパイルエラー
といった、メソッドの呼び出しを強制させる方法は無いでしょうか?



ないと思います。VB.NET(や C#)は、このような制約を課すことができるような言語にはなってないと思います。コンストラクターは特別なものだと考えたほうがよいでしょう。

しいていえば、つぎような感じ(VB.NET が分からないので C# ですけど)で、「メソッドの呼び出しを強制させる」ことを親クラスでおこなうようなメソッド(下記では Func という名前のメソッド)を作っておき、子クラスではそのメソッドをかならず呼ぶように注意するという手はあります。

コード:
using System;

abstract class Foo0
{
    protected abstract void Hoge();

    private void Abc()
    {
        // 子クラスによらず、このクラスでかならずさせたい共通処理。
    }

    protected void Func()
    {
        Abc();

        Hoge();
    }
}

class Foo1 : Foo0
{
    protected override void Hoge()
    {
        // 子クラス固有の処理。
    }

    public void Start()
    {
        // 間違って Hoge() を呼べてしまうけど呼んじゃダメ。

        Func();
    }
}



ただ、(このやりかたをする・しないにかかわらず、)このようなことが必要になるというのは、あまりオブジェクト指向的な設計になってないからだと個人的には思います。もっと、リファクタリングすれば、そもそもこのようなことをしなくてもよいクラス設計にできるかもしれません。ただ、これぐらいのことだったら、それほど大きくはオブジェクト指向から外れていないと思いますので、むりにこれを解消しようとしなくても良いとも考えます。
くまっち
大ベテラン
会議室デビュー日: 2008/01/18
投稿数: 169
お住まい・勤務地: 茨城県のどこか。
投稿日時: 2008-08-06 16:47
よこけんさんが言ってるように
せめてテンプレートメソッドパターンを適用したコードの方が良いでしょう。
*unibonさんのコードを一部修正
コード:
abstract class Foo0
{
    protected abstract void Hoge();

    private void Abc()
    {
        // 子クラスによらず、このクラスでかならずさせたい共通処理。
    }

    public void Start()
    {
        Abc();

        Hoge();
    }
}

class Foo1 : Foo0
{
    protected override void Hoge()
    {
        // 子クラス固有の処理。
    }
}

----------------------------
Foo0 foo = new Foo1();
foo.Start();
----------------------------


unimaru
会議室デビュー日: 2008/08/06
投稿数: 2
投稿日時: 2008-08-06 21:16
必ずメソッドを呼び出さなければならずテンプレートメソッドパターンで解決できる場合はテンプレートメソッドパターンを適用して解決すべきでしょう。

ただ、テンプレートメソッドパターンが適用できない構造(リファクタリングできない状況下)ではJittaさんの言う「例外飛ばせ」が一番無難です。

「実行時にしか分からないバグ」と言いますが、これは「条件によって呼び出す」という制約であれば確かに難しいですが、「必ず呼び出さなければならない」という必須制約であるならテストで十分網羅できると考えられます。

まず、テンプレートメソッドパターンの適用ができるならそうする。適用できないようであれば例外を投げるようにしてテストケースに必ずそのテストが含まれるように工夫するというのでよろしいかと思います。

スキルアップ/キャリアアップ(JOB@IT)