VBAにおけるクラスの継承(擬似)について考える

VBA

PythonやJavaやC++など、オブジェクト指向プログラミング言語ではクラスの継承がサポートされており、保守性や再利用性の高いコードを書くことができます。

そうなると、VBAではクラスの継承(のようなこと)はできるの?と思う方は少なからずいると思います。結論としては、VBAにはクラスの継承に相当するものはありません。
しかし、それっぽいものを擬似的に作ったり、JavaのInterface構文に似たImplementsという機能があるので、今回はそれらを紹介していきます。

①やりたいことのイメージ

例えば、PythonではABC(Abstract Base Class)で抽象基底クラスを定義し、クラスの継承を組み合わせることで下記のようなことが可能です。

このように、基底クラスに各職種で共通の行動や全職で使う内容が異なるものを定義し、継承先クラスには固有の行動を定義するということが簡単に出来てしまいます。

これにより、nameやhpなどのプロパティやdefenseやuse_itemなどの完全に同じメソッドを何度も書く必要がないため、保守性の高いコードが書けることがわかると思います。

本記事では、これに近いことが出来るかをちょっとだけ検証してみた結果を共有します。(もっとうまくやる方法はありそう)

②共通の実装

まず、キャラクターステータス用のCharacterStatusクラスを作ります。

正直、このアクセサを大量に書くのは面倒ですが、ここは我慢しましょう。

次に親クラスとなるParentClassクラスを作成します。

ポイントは、各職クラスで親クラスのインスタンスを持たせる点です。そのために、このように親クラスにステータスを持たせるときれいなりました。(他に最適な方法はあるかもしれません)

③擬似的なクラスの継承

違いはここからです。
③では普通に職種の子クラスを書いていきます。(KnightClass・MageClass・HealerClass)

・KnightClass

・MageClass

・HealerClass

最後に呼び出し処理を標準モジュールに作成します。

それぞれステータスを設定した後に行動させます。

実行結果は次のようになります。

Pythonと比べるとかなり規模が大きくなりますが、概ね似たようなことが出来たかと思います。

一見、もうこの方法で問題ないかのようにも見えますが、実は欠点があります。上記の子クラスであるKnightClassなどを別のプロシージャに渡したい場合、やはりKnightでもMageでも関係なく渡せるようにしたいですね?そうすると引数としてObject型を使って渡すことになりますが、これをすると受け取った側で型が不明な状態になるので、まず自動メンバー表示が使えません。オブジェクトであれば何でも渡せてしまうので、型チェックが効かず、何のエラーが出ているのかわかなくなります。

この辺が悩みどころで、自分しか実装しないから問題なかったり、柔軟に書けるから扱いやすかったりと、メリットもあるので一概にダメと言えないというところですね。

ただ、チームで開発する場合やお客様に納品する場合などは、この実装方法は避けたいところです。

④Implementsを使ってみる

Implementsというのは共通のインターフェースをクラスに持たせる機能です。言葉だけではわかりにくいので、さっそくコードを見てみましょう。下記がIJobインターフェースクラスです。

このように、外部から呼び出すため、publicで宣言だけ書いてあげます。

続いて、各職種の実装クラスを書いていきます。
ここでは、各クラスモジュールにImplements インタフェースクラス(IJob)を記述し、IJobで宣言したプロパティやメソッドは全て実装する必要があります。
その際、メソッド名などの書き方はインターフェースクラス名_メソッド名のような書き方をする必要があります。(書かないとエラーになります)

・JobKnight

・JobMage 独自メソッドMagicをPublicで追加しておきます

・JobHealer 独自メソッドHealをPublicで追加しておきます

最後に呼び出し処理を標準モジュールに作成します。

基本的には③と同様ですね。
異なる点は各playerの宣言はインターフェースクラスで行い、インスタンス生成時に実装クラスにしている点と独自メソッドを呼び出す際は、実装クラスで宣言された変数にキャストするという2点です。

実行結果は③と同じですね。

記述内容が増えただけで、一見すると良さがあまりわかりません。しかし、上記のplayer1,2,3はIJobで宣言されているので、③で書いたように他のプロシージャに渡す際には、IJobとしてどれでも渡すことができます

実はcreateInstanceプロシージャがそのような実装となっています。New JobKnight, JobMage, JobHealer全て渡せて、かつ型安全で、もちろん自動メンバー表示も機能します。

独自メソッドを呼び出す場合にキャストは必要なものの、こちらも安全な実装なので、厳格なコードを書きたい場合は、やはりこの方法がおすすめです。

少し癖があるので、あまり使われていない機能のように感じていますが、十分に活用する価値はあると思っています。

⑤おわりに

いかがでしたか?

いわゆるオブジェクト指向プログラミング言語と呼ばれているJavaやPythonなどと比べると、やや使いにくいのは否めませんが、VBAでもきれいなコードを書きたい方や、クラスの概念について理解を深めたい方にはぜひおすすめしたい内容ということで、紹介させていただきました。

以上、長くなりましたが、最後まで読んでいただき、ありがとうございました。

コメント