• ベストアンサー

クラスを作るとメソッドの数が多くなりすぎる

クラスを作ると,たいがい,メソッドの数が多くなりすぎて,メソッドをさがすのに一苦労します. なにか,クラスのメソッドの設計でいい方法はないでしょうか? メソッドが増えすぎる原因として, ・フィールド変数1つにつき,取得メソッド,設定メソッドで(最大)2つ必要. ということがあります. あと, ・private のメソッド(クラス内部でよく使われる手続きをまとめたもの)が結構必要. ・private のメソッドから呼び出す private のメソッドが結構必要. ということがありますが,publicメソッドがこれらのメソッドと紛れてしまう,ということがあります.

  • Java
  • 回答数4
  • ありがとう数1

質問者が選んだベストアンサー

  • ベストアンサー
  • Healer99
  • ベストアンサー率31% (7/22)
回答No.4

>> 4.privateメソッドの一番外側のメソッドをprotectedにしてそれ >> を内部クラスかスーパークラス化し、コーディングが頻繁に発生 >> する部分のメンテナンス性を向上させる。 >私の基本的知識不足で完全に理解しきれないのですが, >非常に役に立ちそうなテクニックのような予感がします. たとえば doSomething() というpublicメソッドが、doMiddle()というprivateメソッドを呼んでいて、なおかつさらにdoBase()というprivateメソッドが呼ばれているとします。もちろんdoBase()の下にいくつも下位メソッドがあっても構いません。 最初はdoSomething()だけでよかったのが、仕様変更の積み重ねでdoAdd1() doAdd2()と増えていき、そのたびにdoMiddle()に変更が頻繁に発生するがdoBase()は特に変わらないという場合に、メンテしたいのはdoMiddle()だけなので、doBase()はそのクラスの中に実装されている必要はないので、doBase()をprotectedメソッドとした配下ロジックを継承元クラスとして、クラス分けすることができます。 実際にはこんな簡単なケースではないのですが、だいたいぐちゃぐちゃなプログラムというのは、ひとつのメソッドですべて解決しようとしていたり、ロジックが部品化されておらず何百行にわたるメソッドになっていたりします。 それをリファクタリングして、共通に使われる部分、個別で使われる部分の線引きをすれば、共通で使われる部分を継承元として、機能別に小さなクラス(またはメソッド)の集合となり、実際にはかなりの仕様変更に耐えることが多いです。 クラス数が増えることに難色を示す人がいますが、クラス数を増やさないといけないのは、それだけシステムに機能数が増えていることの現れなのです。 また混乱されている原因のうち、プログラマがシンプルに実装出来していない以外の問題として、たまにjavaを正しく理解していない設計者が実権(?)を握っていたりすると、継承回数を抑制したり、機能は減らさないのにメソッド数を抑制したりして実装プログラマや稼動後のメンテナンスプログラマに負担をしいている場合がありますね。 あとアジャイルについては、指摘された本は知りませんが、とにかく「シンプル」に「軽く」作ることですね。

white-tiger
質問者

補足

書いていただいたこと,すべてなるほどです. >共通で使われる部分を継承元として、 >機能別に小さなクラス(またはメソッド)の集合となり、 >実際にはかなりの仕様変更に耐えることが多いです。 メソッドで共通コードを抽出というのは考えたことがありましたが,スーパクラスでというのはちゃんと考えたことがなかったです.なるほど. >クラス数が増えることに難色を示す人がいますが、・・ そうですね. 非常に参考になりました. 

その他の回答 (3)

  • Trick--o--
  • ベストアンサー率20% (413/2034)
回答No.3

どんなクラス設計をしているのかによりますが…… 「private のメソッドから呼び出す private のメソッド」をまとめてひとつのクラスにします。このとき、privateからprotectedに変えます。 今作っているクラスを分離させたクラスを継承する形にします。 継承・スーパークラス・サブクラスは分かりますよね……?

参考URL:
http://www.nextindex.net/java/inherit.html
white-tiger
質問者

補足

「private のメソッドから呼び出す private のメソッド」を減らすという意味で継承を使うという方法があったのですね.なるほど.これならメソッドをまとめて減らすことができますね.

  • Healer99
  • ベストアンサー率31% (7/22)
回答No.2

ソース上に決まったマークをつけると良いかも知れません。 実際は質問者さんの困っているようなクラスは、クラス設計としてはNo.1さんの指摘のように落第なんですが、とはいいつつも昔のシステムをjavaで書き直したり、または下手なプログラマが集まって作ったシステムではメソッドの数がgetter/setterを別としても100ほどあったりして、一体そのクラスが何をするものなのか、あるいはクラス名とは別のクラスになっていたりはちゃめちゃです。 ということで最近はやりのアジャイル的手法な提案ですが、 1.クラスの役割を可能な限り限定する。 2.getter/setterを先頭か最終にまとめて書き、またメソッドも似た機能ごとに分けて書いて、エディタのタグジャンプやマークの機能を活用する。 3.さらに、javaDocコメントを可能な限り完璧に書いて、ある程度コーディングしたら警告すらもないjavaDocドキュメントを作成し(Eclipseでは簡単に作成できますし、ant化も簡単です)、ソースとjavaDocを併用するように心がける。 4.privateメソッドの一番外側のメソッドをprotectedにしてそれを内部クラスかスーパークラス化し、コーディングが頻繁に発生する部分のメンテナンス性を向上させる。 というところでしょうか。私はこれらを実践しているので、自分のソースは勿論のこと他人のソースでもメンテナンスに困ることはあまりありません(数千本のソースを扱うこともザラにあります)。

white-tiger
質問者

補足

大変具体的で,かつ(表現も含めて)丁寧なご回答をありがとうございました! > 1.クラスの役割を可能な限り限定する。 > 2.getter/setterを先頭か最終にまとめて書き、 > またメソッドも似た機能ごとに分けて書いて、 なるほど.そう心がけるようにします. > エディタのタグジャンプやマークの機能を活用する。 これは,メソッドを抽出して,メソッドへのアクセスを良くすると言うことですね. > 3.さらに、javaDocコメントを可能な限り完璧に書いて、ある程 > 度コーディングしたら警告すらもないjavaDocドキュメントを作 > 成し(Eclipseでは簡単に作成できますし、ant化も簡単です)、ソ > ースとjavaDocを併用するように心がける。 Eclipseは使っていますが,javaDocは「併用」とまでは使っていませんでした. 心がけるようにします. (参考にしたいのですが,javaDocは印刷されていらっしゃいますか?) > 4.privateメソッドの一番外側のメソッドをprotectedにしてそれ > を内部クラスかスーパークラス化し、コーディングが頻繁に発生 > する部分のメンテナンス性を向上させる。 私の基本的知識不足で完全に理解しきれないのですが, 非常に役に立ちそうなテクニックのような予感がします. もう少しだけ詳しく解説お願いしてよろしいでしょうか? 情報へのポインタ(本,URL)でも結構ですので・・ > 私はこれらを実践しているので、自分のソースは勿論のこと他人 > のソースでもメンテナンスに困ることはあまりありません(数千 > 本のソースを扱うこともザラにあります)。 大変勇気づけられますし,私も目標にしたいと思います. おかげさまで希望の光が見えてきました. あと,「アジャイル」というのが役に立ちそうなのですが, おすすめの分かりやすい本などございますでしょうか? 検索したところ, http://www.amazon.co.jp/exec/obidos/ASIN/4894715791/ などがひっかかりましたが・・.

  • Trick--o--
  • ベストアンサー率20% (413/2034)
回答No.1

必要の無いものを削る。 外部から参照しない変数にはGet/Setを作らない privateメソッドとpublicメソッドが紛れる、というのは具体的にどういうこと? 命名を工夫したり、書くときに分けて書くように気をつければそんなことも無いと思うけど。 コメントはちゃんと書いてる? コメントを書いておけば、探すときに検索用のキーワードが考えやすいでしょう。 ごちゃごちゃになるのなら、改良の余地があると言うこと。 クラスの継承などを使えば、一つ一つのクラスは小さくなるんじゃないかな。

関連するQ&A

  • Stringクラスのlengthメソッドについて

    こんにちは、Stringクラスのlengthメソッドについて質問させてください。 今まで配列のlengthは、宣言時に長さが決定するからメソッドではなく、finalフィールドで十分。 ArrayListだとかは長さが変わるからメソッドという意識を持っていました。 (カプセル化の概念とも関わりますが) 先日その話しをしていたら、「でも文字列(Stringオブジェクト)の長さも不変だよね。」と言われました。 確かに文字列の長さは不変なのに、長さの取得にはメソッドを使っています。 言語仕様として一貫性を持たせるなら、配列もlengthメソッドにするか、文字列をlengthフィールドにしたほうが綺麗だと思うんです。 Stringクラスのソースコードを見ていたら、文字列の長さは内部的に private int count; と宣言されていました。 そして、lengthメソッドは return count; しているだけでした。 ただ、このcountフィールドに値を代入しているのはコンストラクタ内だけだったので、 public final int length; とすれば、良かったのでは?と思いました。 この考えについて、 それは間違っている、とか歴史的な背景などご存知でしたらご教授ください。 よろしくお願致します。

  • クラスメソッドの仕様

    次のようなクラスメソッドを作りたいのですが、自分で作って見たところ、どのような点を修正すればいいか分かりません。 どうか教えてください。 (1) 次に示す内容を満たすバー(Bar)クラスを作成せよ。 1. バーの右端のx座標(=バーの長さ)、バーの名前を扱う2つのprivateなインスタンス変数を持つ。 2. バーの総数を扱うprivateなクラス変数を持つ。ただし、 ここでいう総数とは、(1)コンストラクタで作成したもの、(2)代入操作で作成したもの、の両方を含む。 3. 引数無しのコンストラクタが呼び出されてバーオブジェクトが作成されると、そのバーのx座標は0以上400未満でランダムに決定され、名前は文字「A」とランダムに決定された0以上10000未満の整数が連接されたものに決定される。 4. バーのx座標を設定するインスタンスメソッドを持つ。 5. バーの名前を設定するインスタンスメソッドを持つ。 6. バーのx座標を取得するインスタンスメソッドを持つ。 7. バーの名前を取得するインスタンスメソッドを持つ。 8. 作成されたバーの総数を取得するクラスメソッドを持つ。 9. 作成されたバーの総数を1増やすクラスメソッドを持つ。 10. 作成されたバーの総数を1減らすクラスメソッドを持つ。 これを自分なりに解釈したところ、 class Bar{ private int x; private String name; private int count; private Bar(){ x=0; count=0; name=""; } public void Bar(){ x = (int)(Math.random()*400); name = "A" + (int)(Math.random()*10000); } public void setBar(int bx){ x=bx; } public void setName(String nm){ name=nm; } public void getX(int bx){ } public void getName(String nm){ } public void getCount(int c){ } } どうか御教授お願いします。

  • クラスメソッドについて

    Kakeibo クラスにあるsyojikin(初期値0)をprivate フィールドとし、その代わりにクラスメソッドshowSyoji(戻り値、引数無し)を用意して、下記のプログラムを作成したのですがクラスメソッドのshowSyojiがうまく回りません。これはもしかしてクラス変数も必要なのですか(privateもつけて)?また、このプログラムはどのようなプログラムになるのですか? class Kakeibo { private int year; private int month; private int date; private int syunyu; private int shisyutsu; private int syojikin; private Kakeibo() { year = 0; month = 0; date = 0; syunyu = 0; shisyutsu = 0; syojikin = 0; } public Kakeibo(int y, int m, int d, int sy, int sh) { this(); if(sy>=0 && sh>=0){ year = y; month = m; date = d; syunyu = sy; shisyutsu = sh; } else{ System.out.println("入力した金額は無効です。"); } } public static void showSyoji() { System.out.println("所持金:"+syojikin+"円"); } public void showData() { System.out.print(year+"年"+month+"月"+date+"日:収入"+syunyu+"円、支出"+shisyutsu+"円\n"); } } class KNO5 { public static void main(String args[]) { Kakeibo.showSyoji(); //Kakeibo kakeibo1 = new Kakeibo(); //kakeibo1.showData(); Kakeibo kakeibo2 = new Kakeibo(2010, 12, 1, 3000, 500); kakeibo2.showData(); Kakeibo kakeibo3 = new Kakeibo(2010, 12, 1, -5000, 300); kakeibo3.showData(); Kakeibo kakeibo4 = new Kakeibo(2010, 11, 7, 0, 1000); kakeibo4.showData(); Kakeibo kakeibo5 = new Kakeibo(2010, 11, 18, 100, 800); kakeibo5.showData(); Kakeibo.showSyoji(); } }

    • ベストアンサー
    • Java
  • クラス変数/メソッドとインスタンス変数/メソッドの見え方について

    Javaの言語仕様(?)についてお教え下さい。 参照変数の型がインスタンスのスーパークラスの型の時、クラス変数/メソッドとインスタンス変数/メソッドの見え方が納得いかずに困っています。 以下のような条件の時です。   ・クラスが2つあり、1つはもう1つのクラスを継承しています。     それぞれを「スーパー」「サブ」と以下で呼びます。   ・インスタンスは"サブ"の型です。   ・上記インスタンスへの参照変数は"スーパー"のクラスの型です。   ・"スーパー"、"サブ"ともに【同名】の「クラス」変数/メソッド、「インスタンス」変数/メソッドがあります。 この場合に、"サブ"のインスタンスを参照している"スーパー"の型の変数を介し、それらにアクセスしたらどれが見えるか?という疑問です。 実験結果では以下のようになりました。           [フィールド]  [メソッド]   [1.static ]  スーパーの   スーパーの   [2.非static]  スーパーの   サブの 納得いかないのは「2.非static」で「フィールド」が、「スーパーの」になるところです。 これも「サブの」になると思っていました。 なぜサブクラスのが見えないのでしょうか? 同名の変数なのでスーパークラスのはサブクラスので隠れされ、サブクラスのが見えると思っていたのですが。 参考書には以下のように書いてありました。   フィールドの場合、参照変数の型のものが見える。   メソッドの場合、インスタンスの型のものが見える。 私には不自然に感じられるのですが、「こういう仕様だから。」と納得するしか無いのでしょうか? 「なぜこうなるか」について説明がある文献、サイトなどありましたらお教えください。 参考までに以下が実験したサンプルコードと結果です。長くて申し訳ありません。 「サンプルコード」 public class Super { static int staticField = 10; int instanceField = 100; static void staticMethod() { System.out.println( "staticField = " + staticField ); } void instanceMethod() { System.out.println( "instanceField = " + instanceField ); } } public class Sub extends Super { static int staticField = 90; int instanceField = 900; static void staticMethod() { System.out.println( "staticField = " + staticField ); } void instanceMethod() { System.out.println( "instanceField = " + instanceField ); } } public class TestStatic { public static void main(String[] args) { // インスタンスはSub、参照変数もSub、という状態。 Sub sub = new Sub(); System.out.println( "実験1" ); System.out.println( "1.クラス変数      " + sub.staticField ); System.out.print( "2.クラスメソッド    " ); sub.staticMethod(); System.out.println( "3.インスタンス変数   " + sub.instanceField ); System.out.print( "4.インスタンスメソッド " ); sub.instanceMethod(); // インスタンスはSub、参照変数はSuper、という状態。 Super sup = new Sub(); System.out.println( "実験2" ); System.out.println( "5.クラス変数      " + sup.staticField ); System.out.print( "6.クラスメソッド    " ); sup.staticMethod(); System.out.println( "7.インスタンス変数   " + sup.instanceField ); System.out.print( "8.インスタンスメソッド " ); sup.instanceMethod(); } } 「結果」 実験1 1.クラス変数      90 2.クラスメソッド    staticField = 90 3.インスタンス変数   900 4.インスタンスメソッド instanceField = 900 実験2 5.クラス変数      10 6.クラスメソッド    staticField = 10 7.インスタンス変数   100 8.インスタンスメソッド instanceField = 900 納得が行かないのは7のところです。 以上よろしくお願いいたします。

    • ベストアンサー
    • Java
  • Java 静的メソッドとインスタンスメソッド

    静的メソッドとインスタンスメソッドの使い分けがよくわかりません。 私の認識は 静的メソッド:インスタンスメンバ変数を参照する必要がない処理 インスタンスメソッド:インスタンスメンバ変数を参照して行う処理 と思っています。 よって、例えばDAOを作成する場合、select、update、insertを実行するメソッドを作成しますが、これらはクラスのインスタンスメンバ変数を参照する必要がないので静的メソッドにするべきだと思っています。 しかし、本やネットのDAOのサンプルプログラムはインスタンスメソッドで作成されています。 これらは、private static String の変数(SQL文が記述されている)を参照していますが、インスタンスメンバ変数は参照していません。 なぜselect、update、insertのメソッドをインスタンスメソッドにする必要があるのかわかりません。 静的メソッドとインスタンスメソッドの使い分けの基準を教えていただけないでしょうか。 よろしくお願いします。

    • ベストアンサー
    • Java
  • どのクラスのメソッドか、をどう見極めるか。

    どのクラスのメソッドか、をどう見極めるか。 Java初心者です(教科書で学んで、実践はこれからというレベル)。 参考書やネット上の資料等に掲載されているコードを見ていますと、 import文(10文くらい)で沢山のパッケージをimportしているようなクラスを しばしば目にしますが、このようなクラス内で使われている沢山のメソッドは、 それぞれ、どこかのクラスに属しているメソッドであるかと思います。 これらのメソッドについて、その仕様を知りたいと感じた場合、 それらがそれぞれ、どのクラスに属するのかを突き止める必要があるかと思いますが、 その突き止め方について、どなたか教えて下さい。 (一般的に普及している方法で結構です。) 例えば、知りたいと感じたメソッド名をネット検索し、 そのメソッドが「Javaの組み込みクラス」のメソッドである場合には、 ネット検索でヒットするでしょうから、その検索結果を受けて、 そのヒットしたクラスと、import文の内容とを比較し、 ネット検索でヒットしたクラスが、そのメソッドの格納主であると確信できれば、 それをもとに、そのメソッドの仕様を知ることができますよね。 (自作・他作のメソッドと、名前がバッティングしているかもしれないことを考慮すると、 やや頭が痛くなる問題になりませんか?) ネット検索で辿る方法が、まず頭に浮かびましたが、 これよりも効率的な方法がもし何かありましたら、教えて下さい。 ただ、一方で、 仕様を知りたいと思っているメソッドが、 「Javaの組み込みクラス」のメソッドではなく、 自作(もしくは、他作)のメソッドであった場合、 検索してもヒットはしませんから、その場合には、 import文にある自作もしくは他作のパッケージをしらみつぶしで探していくことになるのでしょうか? 当然、そのメソッドは、同一パッケージ内にあるクラスのpublicメソッドである可能性もありますから、 同一パッケージ内のクラスの中も、しらみつぶしに探していくことになりますよね? 各メソッドがコメントで「○○クラスのメソッド」というように注意書きされてあれば、 このような苦労はないのでしょうが、ネット上のソースを見る限りでは、 そんな親切なコメントはまず期待できないように思います。 以上、まとまりのない質問ではありますが、アドバイスを宜しくお願い致します。 自分のこの疑問が見当違いの疑問でしたら、その時は、ズバリそれを指摘して下さい。

    • ベストアンサー
    • Java
  • 親クラスと子クラスのフィールドとメソッドについて

    親クラスと子クラスのフィールドとメソッドについて 以下のサンプルソースを実行した時の動作の原理について 教えてください。 oya型変数にkoクラスのインスタンスを作成した場合、 メソッドはkoクラスのものなのに、 フィールドはoyaクラスのものになるということが イマイチすっきり理解できません。 どういうことなんでしょうか。 ------------------------------------------------------- [ソース] public class exec { public static void main( String args[]){ oya obj = new ko(); System.out.println(obj.str_field); obj.disp_field(); } } public class oya{ String str_field="親実行"; public void disp_field(){ System.out.println(str_field); } } public class ko extends oya { String str_field = "子実行"; public void disp_field(){ System.out.println(str_field); } } ------------------------------------------------------- [実行結果] > 親実行 > 子実行 -------------------------------------------------------

    • ベストアンサー
    • Java
  • メソッド宣言の戻り値の型にクラス名を使うには?

    メソッドの戻り値の型にクラス名を使ってるプログラムを見かけたのですが、例えばクラス名を public class Player{ とします。そして Playerクラスのメソッド宣言に  private   Player(戻り値の型) startRun(メソッド名) { とあります。 これは戻り値の型にクラス型の変数を使ってユーザー定義してると思うのですが使い方が分かりません。 javaのサイトはできるだけ調べたのですが戻り値の型にクラス名を使うにはどうすればいいか分かりませんでした。 この使い方を教えてくれるサイトを教えてください。 基本型と参照型のStringクラスについて教えてくれるサイトはたくさん見かけたのですが…。 お願いします。

    • ベストアンサー
    • Java
  • クラス、インスタンスメソッドについて

    JAVA初心者です。 現在、先人が作ったプログラムの修正作業を行っておりますが、 以下の点に疑問があります。(因みに、先人はJAVAのスペシャリストではありません。) あるクラスが以下の様になっております。 public class Sample { private static Sample s = new Sample(); private Sample() { } /** クラスメンバに存在するインスタンス取得 * @return Sampleクラスの唯一のインスタンス */ public static Sample getInstance(){ return s; } public static void methodA(){ ... } } でこのmethodAを使用するには、以下の様にします。 Sample.getInstance().methodA() これはこれで納得で、うまく動作しますが、これは 結局の所、クラスメソッドにしたかったという事ではないのかな?と 疑問に感じています。つまり、単純に Sample.methodA と呼び出せばうまくいきます。 ところが、たまたまAPIドキュメントを見ていた所、Calendarクラスにもやはり getInstanceというものが存在し、現在日時を取得するのに Calendar.getInstance().getTime() の様に呼び出すと書いてありました。 Sampleクラス、JAVAのCalendarクラス(これに限った事では無いとは思いますが) のこれらのgetInstanceの効用とはなんなんでしょうか? ・クラスの外でnewでインスタンスを作り出さない所 ・それでいてクラスメソッドではない(?)所 この辺りについてご回答よろしくお願いします。

    • ベストアンサー
    • Java
  • staticメソッドにするかどうかの判断

    staticメソッドの使いどころについて質問させてください。 まず、メソッドの内部で、そのメソッドが定義されているクラスのイ ンスタンス変数を使用している場合は、そのメソッドはインスタンス に依存するので、インスタンスメソッドにしかできないのはわかり ます。疑問なのは、「じゃあこのメソッド内でインスタンス変数を使 わないで引数で渡せるように作れば、インスタンスに依存しないの でstaticにしていいの?」(※)ということです。 さらにこうも思います。 なんとなくですが、※のようなことをしたらオブジェクト指向の意味 がない気がします。理由ははっきりわかりません。ほんとになんとなく です。(奇跡的にあたっていたとしても、理由を教えて下さいm(_ _)m) そして、さらに混乱するのが、ユーティリティの関数などでstaticメ ソッドになっているのを見ました。この場合はどうしてメソッドの引 数を指定するようにしていて、クラスのインスタンス変数を使うこと はしないのか。 以上、大変下手な文章ですが、混乱しているポイントが伝わったでし ょうか? よろしくお願いします。

専門家に質問してみよう