質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

Q&A

解決済

5回答

26481閲覧

javaで、引数が多すぎるときの対処法

退会済みユーザー

退会済みユーザー

総合スコア0

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

0グッド

3クリップ

投稿2016/07/27 04:05

編集2016/07/27 04:06

オブジェクト指向を意識したことがないのでオブジェクト指向の設計をしようと学習していますが、なんだかよくわからなくなってきました。

例えば一月分の予定を入力するカレンダーのようなプログラムを作る場合、
一ヶ月分のカレンダーに、日付ごとの入力フォームをつくり、入力された内容をDBに保持するプログラムとします。
DBのレコードは1日ひとつ、項目には1日単位の年月日、イベント名、起床時間、持ち物、予算などがあり今後も増える可能性があるとします。

このケースでは入力画面からDBに書き込むSQL文を発行するまでに、日付単位で管理するべき情報をもったオブジェクトが毎月30個ほど作られることになりますよね?
となるとそれらのオブジェクトを生成するために引数として入力画面から5つのデータを渡すことになると思います。

引数5つでもプログラムとして多すぎる気がしますし、今後も増えていくとしたらただ羅列するのは可読性が悪いので他の方法を取るべきだと思います。
でもセッターでフィールドに逐一値を入れていくのも不自然で無駄が多い気がしますし、
配列などに入れてデータを渡すのはオブジェクト指向らしくない気がして、どうすればいいのかわからなくなってきました。

この例は素人が適当に作ったので根本的に考え方がおかしいところもあるかもしれませんが、
オブジェクトが管理するべき引数が多くなることってありますよね?
そういったときはどう対処すればいいのでしょうか。

また、DBからデータを読み込んで表示するときには、この日付ごとのデータを保持したオブジェクトから画面描画オブジェクトにインスタンス変数を渡すことになると思うのですが、
この場合にはフィールドをpublicにして直接参照するか、全ての変数にgetterを設定して逐一渡していくか、配列などに入れてまとめて渡す方法しか浮かびません。

フィールドがpublicなのは良くないと聞きますし、getterを使うべきではないという意見も見ます。
配列は求めているデータがどこに格納されているのか識別できず、配列を作ったクラスを閲覧しなければいけないのでカプセル化に失敗している気がします。

何かいいやり方はないのでしょうか。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2016/07/27 04:14

長い文章で説明するより、実装を見せたほうが、回答者に伝わりやすいと思います。関数の中身はなくても、in out を示すだけで十分かと。
guest

回答5

0

ベストアンサー

引数が多くても、その順番に意味があれば特にかまわないと思います。Calendar.setは6個も引数を取りますが、とりわけおかしなモノではありません。しかし、Calendarは特殊な例として、順番に意味がない場合は多すぎると混乱の元になります。では、そのような時はどうしているかというと、名前付き引数を使って順番を無視できるようにしたりします。でも、残念ながらJavaには名前付き引数がありません。他の手段として、連想配列(Map系のこと)を渡すという方法がありますが、JavaにはMapのリテラルが存在しませんし、静的型付けのためvalueが全部Object型というあまりしたくないものにできあがります。仕方が無いので、setterを作って、せっせと一個一個入れるというのもこれまた本末転倒です。

では、どうすべきか。答えは簡単です。元をそのまま投げ込めば良いのです。今回の例ですと、

  • 入力画面のフォームから送られてきたデータ
  • DBから読み込んだデータ

の二つでしょう。フォームのデータをバラバラにして引数として渡すのでは無く、フォームのデータを取得するオブジェクトをそのまま渡せば良いのです。DBも同じで、クエリ結果をそのまま引数として渡せば良いのです。どちらも引数が一つで済みますよね?フォームのデータやクエリ結果をチェックしたり分解したりするのが各クラスごとになってしまうと思っていませんか?それこそ継承を利用してうまく共通化すれば良いだけのことです。

そういう所を突き詰めて共通化していくと、ORMやフレームワークになります。車輪の再発明が嫌なら、適当なフレームワークを使った方が良いでしょう。


そうそう、「getter/setterは避けるべき」というのは「(何も考えずに全てに)getter/setter(をつけるの)は避けるべき」という意味ですよ。今回の例ですと、たぶん、LocalDate getLocalDate()というgetterはたぶん必要になるかも知れません。ただ、フィールドにLocalDate localDateが存在する必要は無く、別の方式でフィールドを持っても良いし、その都度生成してもかまわないのです。

投稿2016/07/28 22:32

raccy

総合スコア21733

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2016/08/03 12:05

おお、求めていたのはまさにこれです。 初心者なので正しい理解かはわかりませんがこれこそオブジェクト指向っぽい気がします。 引数をオブジェクトにすればアクセッサメソッドを使わないことも実現できそうです。 ちなみにgetterやsetterが良くないという意見は、おそらく単にデータをゲットしたりセットするだけのメソッドは不要であるという意味なんだと思います。 何らかの処理の結果としてデータをゲットしたりセットするメソッドならもう少し違う命名にできる、 あるいは、インスタンスの一部のデータを使用して他のクラスで行う処理があるなら、そのインスタンス内のメソッドにしたり、そのデータとそれに関する処理をまとめたオブジェクトを作るべき。 そんな意味だと理解しました。
guest

0

引数が多いと思うならば1つのクラスとして束ねて、一括でバインドできる仕組み(Commons-OGNLなど)を用いる手法がありますが、特段これはオブジェクト指向ではなく、より良いコーディングのための手法ではないかと。

投稿2016/07/27 04:32

A-pZ

総合スコア12011

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

まずは突っ込みどころからですが、

DBからデータを読み込んで表示するときには、(中略)getterを使うべきではないという意見も見ます。

「データを取ってくること」自体が目的のオブジェクトなので、getterを付けないほうがむしろ不自然な設計だと思います。

あと、「いくつもセットになったデータ」を扱うときには、「Value Object」といって、「メソッドは何もなしで、publicフィールドだけが用意してある、C言語の構造体のようなオブジェクト」を使うという手法もあります。

投稿2016/07/27 04:16

maisumakun

総合スコア145121

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2016/07/27 05:32

getter/setterはオブジェクト指向としてよろしくない、といったような話を何度か見ましたが使ってもいいのでしょうか? とりあえずsetterを使うべきではないという意見は納得できたので、コンストラクタを使うように考えを改めました。 getterについても意見としては納得できましたが方法がわかりません。 一般的なgetterの使用を避ける方法があるものかと思っていましたが、そんなものはなく使用するのが普通なんですかね? value objectは求めているものに近そうな気がします。 調べてみます。
maisumakun

2016/07/27 05:43

文脈がわからないのでなんとも言えないのですが、「外部から直接アクセスする必要のない情報」に対してgetter/setterを用意するのがよくない、みたいな流れだったのではないでしょうか。publicフィールドを用意する、package-privateにして別クラスからアクセスさせる、リフレクションをかけるといった無理やりな方法を別にすれば、外部から状態を取得したい場合には(getterと名乗るかどうかは別として)メソッドを呼ぶのがいちばん素直な手段です。
guest

0

オブジェクトが管理するべき引数が多くなることってありますよね? そういったときはどう対処すればいいのでしょうか。

私は、それぞれのフィールドにセッターを用意するのが良いと思います。

5つの引数を取るメソッドを用意するのは、お勧めできません。
『Effective Java 第2版』の P.182 に、以下の記述があるからです。

長いパラメータのリストは避ける。4個以下を目標にしてください。ほとんどのプログラマは、長いパラメータリストを覚えられません。 (中略) 同じ型のパラメータが何個も続くのは、特に有害です。 ユーザがパラメータの順序を覚えられないだけでなく、順序を間違ったりしても、プログラムはコンパイルできて実行できます。 ただ、作者の意図通りには動作しないだけです。

でもセッターでフィールドに逐一値を入れていくのも不自然で無駄が多い気がしますし

フィールドの数が10個も20個もあるとさすがに再設計した方が良いと思いますが、5個程度であれば、十分、許容範囲だと私には思えます。

配列などに入れてデータを渡すのはオブジェクト指向らしくない気がして

「オブジェクト指向らしさ」がどのようなものかは私には分かりませんが、少なくともバグを生みやすい設計ではあります。
この方法は、前述の

同じ型のパラメータが何個も続く

と同じことが起き得るからです。

また、DBからデータを読み込んで表示するときには、(中略)何かいいやり方はないのでしょうか。

これも、素直に

全ての変数にgetterを設定して逐一渡していく

のが良いと思います。

フィールドをpublicにして直接参照する

のは"カプセル化"の原則に反しますし、

配列などに入れてまとめて渡す

のも、特にメリットのある方法とは思えません。

実際にプログラムを書いてみると分かりますが、結局は、その配列から個々の値を取り出す処理を書くか、配列に格納された要素の順番と数に依存する、危険なロジックを書かざるを得ないからです。

getterを使うべきではないという意見も見ます。

については、私もmaisumakun様の回答およびコメントに同意です。

あらゆるケースに適用できる万能の手法、というものはありません。
誰かの意見を見聞きした場合は、必ずその文脈(※1)や背景(※2)、メリット・デメリットにも注意することをお勧めします。

※1 「○○の場合は」などの"ただし"書きのこと
※2 どのような問題に対処したときの話なのか、ということ

投稿2016/07/28 17:29

KiyoshiMotoki

総合スコア4791

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

大筋の方法としてはそれでいいんじゃないでしょうか?

でもセッターでフィールドに逐一値を入れていくのも不自然で無駄が多い気がしますし

別に不自然でも無駄でもないと思いますよ。
もしくはパブリックメンバーにして直接値を代入してもいいです。

配列などに入れてデータを渡すのはオブジェクト指向らしくない気がして

そんなことはないです。
配列とはあくまでデータ型ですのでオブジェクト指向でもよく使用しますよ。

それよりも、ループが多用されるでしょうから、インスタンスのリサイクルをしっかりやれば問題はないと思いますよ。

投稿2016/07/27 04:21

youcova

総合スコア20

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問