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

VBA

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

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

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

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

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

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

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

②共通の実装

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

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

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

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

③擬似的なクラスの継承

各職クラス(子クラス)を書いていきます。(KnightClass・MageClass・HealerClass)

まず、KnightClassからです。このクラスは独自メソッドを持たず親と同じ動きをしています。
Attackでポリモーフィズムのようなものを実現しています。

・KnightClass

・MageClass 独自メソッドMagicを実装します。

・HealerClass 独自メソッドHealを実装します。

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

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

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

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

全職で共通の要素をParentClassに作り、各子クラスでは、親インスタンスを介してそれらを使用することができます。(擬似継承)

また、今回のAttackのように、子クラス毎に動きを変えたい場合にも対応可能です。(ポリモーフィズム)

一見、この方法で何も問題ないかのようにも見えますが、実はいくつか欠点があります。

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

このような実装は規模が大きくなるとバグの温床となる可能性があるので注意が必要です。

とはいえ、実際のところ自分しか触らないから問題なかったり、柔軟に書けるから扱いやすかったりと、メリットもあるので一概にダメとは言えません。実際に使うかはケースバイケースということになります。

ただ、チームでの開発や顧客へ納品する場合などは、このような実装方法は極力避けた方が無難ですね。

④おわりに

今回の内容はここまでとなります。
書き方を工夫することで、クラスの継承のようなものを実現できることがわかりました。しかし、いくつか課題は残るため、解決策が求められるという内容でした。

次回はImplementsを使って、インターフェースクラスを作ることで、今回の課題を解決できるか見ていきます。

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

次の記事