UIとロジックを分離する

2018年9月27日

最近、ツールの設計ということに目が向くようになってきました。Pythonが主流になったことによると思います。

Pythonでのツール開発の場合、やはりUIとロジックは厳格に分離した方が良いです。なぜかと言えば、UIはQtDesignerを使って感覚的に作り、ロジックはエディタでゴリゴリと書きたいからです。途中でUIの仕様が変更になったりした際に、UIを書いているPythonファイルに動作のロジックも書いてしまうと都度書きなおしになるため、QtDesignerでのUIカスタマイズができなくなってしまいます。

そのため、UIのクラスを継承してツールのクラスを作る、というようなことから始めました。

次に、汎用性のあるツールの開発で、全く同じ機能を持つツールを3dsmaxとMotionbuilderの両方で使いたい、という要望が出てきました。当然の要望と言えます。

そこで、UIは完全に共通にし、それを継承したクラスとして共通の処理をもつ抽象クラスを作り、さらにそれを継承して3dsmax用とMotionbuilder用を作る、というような構造にしました。これが非常に便利です。

そんなもの当たり前だという話なんですが、これまで「継承」という発想のないMaxScriptが開発の主軸だったため、こういうオブジェクト指向ならではの効率化にまったく目が向いていなかったのです。

Pythonでこれをやりだしてから、MaxScriptオンリーでツールを書く際にもUIとロジックの分離ということを意識するようにしました。

MaxScriptにはクラスというものはありませんが、マクロスクリプトツールは使用するデータとメソッドがパッケージされているという意味でクラス的です。(継承はできないのでいわゆるオブジェクト指向のクラスとは違いますが)

ロールアウトの中にそこで使うデータ変数を置き、イベントハンドラやハンドラから呼ばれる関数を定義する、というような書き方をするのが一般的だと思いますが、これだとUIとロジックはがっぷり四つ状態でがんじがらめです。

そこでこれを分離したいわけですが、オススメは構造体を使うことです。メソッドとデータをまとめた構造体を定義し、ロールアウト側でその構造体をインスタンス化して使います。

このような設計でツールを作っておくと非常に多くのメリットが得られます。構造体にしてあるとコマンドラインから呼び出して処理を実行することができます。つまり、別のツールから機能を再利用したりすることができるわけです。

実は今回、この設計にしておいたことで非常に助かった例がありました。

構造体を用いてUIとロジックを分離して作ってあったMaxScriptのツールで、ユーザからUIに関しての要望が出されました。その要望はMaxScriptのUIでは実現できないもので、逆にPySideを使えば楽勝、という話でした。

そこで、PySideでUIを作り、それを継承してツールのクラスを作り、そこからMaxScriptの構造体を呼んでメソッドを実行する、という仕組みで接続しました。

これにより、100%MaxScriptで書かれていたツールのUIだけをPySideに置き換える、といったことが実現できたのです。

ちなみに3dsMax 2017から実装されたpymxsというモジュールを使うとかなり柔軟にPythonからMaxScriptを実行できます。これを使えばこのような非常に柔軟にPythonとMaxScriptをまたいだツール開発ができてしまうのです。

ただ、pymxsがあるのとないのとではまるで開発効率が違うので、このようにPythonとMaxScriptをまたぐものをやりたい場合は3dsmaxは2017以降を使うのが良いでしょう。

この辺の話はいずれサンプルコードを用いて具体的に解説してみたいと思っています。