woshidan's loose leaf

ぼんやり勉強しています

Bridgeパターン

「機能のクラス階層と実装のクラス階層」

「機能のクラス階層と実装のクラス階層」ああ、そういう言葉あったわーというか、なんか最近そう言うの書いたかもしれない、 ということをふまえながら、読んでみます。

機能のクラス実装は、

新しい機能を追加したいと思ったときに、クラス階層の中から自分の目的に近いクラスを探し出し、そのサブクラスを作り、目的の機能を追加した新しいクラスを作る...。これが機能のクラス階層です。

実装のクラス階層は、

の分担をスーパークラスとサブクラスでやるためにクラス階層を使う。

違いました。

最近やったの、目的に近い処理を書いてあったクラスがあって、それとほとんど同じ流れで別の実装をするクラスを書きたかったので、同じ流れの部分をモジュールに括り出して、includeさせたんでした。

サブクラス的なのが先にあって、スーパークラス(というかモジュールなんだけどRubyだとモジュールが実質的にスーパークラスの位置に来る)に持って来たんでしたわ。

で、そのモジュールはどこへ置いたらいいんだっけ?って迷ったんですね。三週間くらいしたら、この時の仕事の事なんかどうでもええわ!ってなるだろうけど。

さて、

「機能のクラス階層」と「実装のクラス階層」を2つの独立したクラス階層に分けてしまいましょう

というのをどういうことか注意しながら読んでみます。

委譲について

とりあえず、自分は委譲というのをその機能をメソッドに足すのではなくて、他のそのメソッドを持ったクラスのインスタンスを持つことにして、それを使う、というのをなんか誤解してるっぽい気がします。

何だろ、そういうとき、モジュールに括り出して、モジュール入れるような考え方になってる。

Rubyでこれまで書いてきた手応えだと、基本的に、メソッドがモジュールになっていないものを流用したい場合(ここでいう機能の階層)は継承を使う。

複数継承させたい場合、メイン以外のものをモジュールに括り出せないか、考えてモジュールを使う。 なんとなくインスタンスを作成しないのだったら、モジュールにしそうな感じだ。

モジュールや継承では不都合が多すぎる(例えばコアクラスの一部に修正を加えたかっただけなのに思ったよりも書き直しが多くなりそうな)場合は委譲を使う、という風になっている。

ダックタイピングに慣れすぎた...?

なんでそういうことを言ったか、というと例のStringDisplayImplがDisplayクラスで利用できるのが少々分かりにくかったため。

StringDisplayImplクラスはDisplayImplクラスの抽象メソッドを実装しているサブクラスなので、DisplayImplクラスとしても扱えるんですね。

それで、StringDisplayImplクラスを使いたいかどうかは、Displayクラスのインスタンスを作るときに、委譲用のインスタンスを渡すときに決める、と。

CountDisplayクラスもDisplayクラスを継承しているので同じように扱えるし、さらに書き足したメソッドが使える、と...。

どちらかというと、「機能の階層」が「処理の流れを扱う」系統に、「実装の階層」が「処理の詳細を扱う」系統に思えて、実装の方は言葉通りなんだけど、機能が自分の中で実装と別れてないのかもしれない。

自分の中で「大きな処理の流れ」 =「 機能」なんだろうか。一回、機能って言葉だけ聞いたらどれくらいの単位のコード思い浮かべる?って聞いたら面白いかもしれない。

あと、やっぱり、このへんはRubyだとサブクラスはスーパークラスと同じように扱えるというより、同じモジュールをincludeしている同じインタフェースを持っているクラスは同じように扱える(ダックタイピング)の方が主流だから、久々にあれ?ってなったのはあり得そう。面白いな。

追記

CSS 設計の長い夢 - ペパボのフロントエンドスタンダード

上のフロントエンドの話読んでて、Bridgeパターン、たぶん、scssで使うと良いんだと思った。

追記2

一昨日の記事を読み直してたら、 やっぱり、委譲の方がいいじゃん!ってなったけど、 やっぱり、その、クラスじゃないと実装できない、みたいなのが見えてないかもだけど..。

機能と実装、と言われるからうーんって感じだったけれど、Bridgeパターン って、

  • 一定の単純なメソッドを組み合わせて使うメソッドを持ったクラス(Abstraction)
    • 同じものを5回書いたり、強調して書いたり、やりたいことのかたまりでメソッドを書く
    • 機能
      • やりたいことを増やしたくなったら、サブクラスの形で増やす(RefinedAbstraction)
  • 一定の単純なメソッドを持っているクラス(ConcreteImplementor)
    • HTMLで書いたり、txtで書いたり、みたいな。具体的にどうするか、のかたまりでメソッドを書く
    • 結城さんの本で言う、実装

に分けて書きましょう、という話だった。

それで、Javaの場合は、一定の単純なメソッドを持っているクラス達が何が出来るか、を スーパークラスで決めるようにしておくと便利!(Implementor) という話だった。

Rubyでもそうなんだけど、Rubyだと、抽象メソッドってのが無くて、 インタフェースが本当にちゃんと決まっているかを保証するにはテストを書くしないのだ......。

あと、どっちかっていうと、クラスをぼこぼこはやしていくのは困るから、 ってのに経験不足で実感が無くて、

それぞれに分けた方が考えやすいですよね。

でもインタフェース考えないと後で結合するときめんどくさいですよね。

インタフェース、最初にImplementorとAbstractionで決めておきましょうか、 の方がぴんと来るかもしれない。プログラムの場合は。

階層が混じっちゃうよね、というのはCSSの話の方がぴんと来るなぁ、触ってて。