著作一覧 |
いや、本物を見るとは思わなかったがすさまじく強力でびびった。ものはセッタインジェクションがからんでいる超弩級のオーバーライドだったのだが、以下はそれを甘ちゃん化したもの。
public class Root { private String name; public void setName(String newName) { name = newName; } public void printName() { System.out.println("my name is " + name); } }まあ、どうでも良いクラスなのだがセッタインジェクションの対象となるフィールドとセッタを定義したクラス。
public class Extended extends Root { private String name; public void setName(String newName) { name = newName; } public static void main(String[] args) { Extended e = new Extended(); e.setName("watashi ha nakano"); e.printName(); } }
で、問題のクラス。実行すると当然、次の結果となる。
$ javac *.java $ java -cp . Extended my name is null $
こういうものをどうすれば作らせないですむかをちょっとディスカッション。
プログラマが100人の村だとして、たった1人でもこういうとんでもないのが紛れ込んでいたら、全部staticメソッド(フィールド利用禁止)にしようホトトギス、と考えたくもなるがそれは無理なので実装継承禁止だホトトギス。
いや、直して見せようホトトギス。でもどうやって? 全部チェックできるのか? そんなときのFndBugsFindBugsだホトトギスとか。
フィールドを直接参照禁止だホトトギス。常にゲッタを使えば済むんじゃないか。いえいえそれは無理でしょう。フィールドを直接さわりたいからオーバーライドしたのじゃないかなホトトギス。privateが問題なのだよホトトギス、パッケージプライベートにしとけばこんなことはしなかったんじゃないのかな(と、これはまじめな考察である)。
結局、コピペできなくすれば良いのだホトトギス。DOSで開発させようホトトギス。それは何がなんでも非効率ではなかろうか? いや、こんなプログラムを量産されるよりは効率的だぞホトトギス。そうは言ってもホトトギス、一生懸命基底クラスの内容をDUPするかもホトトギス。copy Root.java Extended.javaとかしてから編集するかもホトトギス。と、世にぬすっとのネタは尽きマジ。
というか、フィールドオーバーライドだけなら良くはないけどまだ救いはあるのに、なぜセッタまでオーバーライドしたんだろうか(セッタをオーバーライドしなければRootクラス側のフィールドに入る。とは言えExtended側でもフィールドを参照しているメソッドが実際にはあるからだめなんだけど)。とまじめに考察してみる。クラスをまたがってリファクタリングして重複しているセッタとフィールドを基底クラスに汎化して、しかし特化クラス側から削除を(好意的に取れば)忘れた、あるいはもったいないお化けに取り憑かれたか。だろうな。リファクタリングに情けは無用。移動したならばっさり削除。というか、ユニットテストしてないだろうな。それはリファクタリングではなく、バグの培養というべき行為だ。
手続き型を関数言語と呼ぶのはあ、突っ込まれたほうの言い方だったのですか。それは残念というか。
ジェズイットを見習え |
おそらくTYPOです。FndBugs → FindBugs<br>いろいろ大変なソースコードと格闘なさってらっしゃるのですね。ごくろうさまです。
つぎのどれががいいと思います.<br>(1)フィールド名には担当者の名前を含ませる。 (2)C#に鞍替えする。 (3)extendsを禁止。 (4)extendsは許してもフィールドの追加は禁止。
たまに他人の名前書くやつがいるなぁ…
いがぴょんさん、ご指摘ありがとうございます。修正しました。<br>unibonさん、(2)は長い目で見ると良い選択か、と僕も思いました。ビジネスロジックだと(3)が相当現実的だと思います。でも、わかってなければわかってないほど使いたがるんですよね、これが。<br>通りすがりさん、トリプルミーニングなんですが、どれなんでしょう? 1)watashi ha nakano(Wnn崩しなんで突っ込まれてもちょっと困る) 2)ツッコミ者の誰かが他人の名前(つか、わからないけど) 3)unibonさんの案1) の運用の話(そりゃイヤかも)。
ソースファイルの頭に概要説明&署名(作成者とか)する規約になってて、その部分だけコピペするのはいいけど、署名を書き直さない人いますよね。<br>問い合わせがコッチにくるので勘弁して欲しい。そういう人に限って「こんなコード書けねぇよ」と萎えるようなコードを書くんだよなぁ。
やっぱそっちかな。<br>cvsなどを利用して$Log:$とか$Id:$とかを埋め込んでコミット者がわかるようにする、で相当解決できると思います。<br>代理コミットの場合は連帯責任ってことで。
あまり解決になってないかもしれませんが,セッタは必ず final にするのはどうでしょうか.
それは一瞬良い手に見えたけど、だったら自分が使うリソースのために実装継承すること自体が間違いだと思うけど。<br>#テンプレートメソッドの実現のためにコードを(狭い範囲で)使うための実装継承くらいしか使わせたくないな。<br>と書いてから、逆にリソースだけを継承して、コードを完全に分けるという方法論も有り得るのか、とも思った。<br>ちょっと検討対象にします。どうもありがとう。
と思ったけど、セッタがfinalでもフィールドのfinalは意味が違うからセッタインジェクション自体ができなくなってしまいます。つまりそれではフィールドはオーバーライドできるから解決にならないです。でも、セッタのオーバーライドは防げるからましかな。