🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Java

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

オブジェクト

オブジェクト指向において、データとメソッドの集合をオブジェクト(Object)と呼びます。

Q&A

解決済

2回答

1091閲覧

クラスの関係をどうすればいいかわからなくなりました

rimokonTenko_mo

総合スコア12

Java

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

オブジェクト

オブジェクト指向において、データとメソッドの集合をオブジェクト(Object)と呼びます。

0グッド

0クリップ

投稿2019/10/30 14:34

編集2019/10/31 09:58

前提・実現したいこと

独学でオブジェクト指向を学習している者ですが、依存関係をなくそうとして、依存先のクラスの命令を受けて動くようにクラスを作っています。そうすると、命令を受けるだけで、逆に、命令を出したいようなときに、どうすればよいかわからなくなってしまうのです。例えば、サッカーチームの監督がいて、監督(メインクラス)が、選手(小クラス)に命令をするようにクラスを作ったほうがいいと聞きました。(間違って捉えているのかもしれません。)すると、監督が選手の状況を感知して、他の選手に命令することができても、選手同士で命令(攻撃)をするのができない気がするのです。もっと複雑な構造になってくるとなおさらです。

今、日(Day)をデータとして持っていてクラスがあって、日ごとに予定(Plan)と完了したこと(CompletePlan)があるとします。そのような構造で、Planから他のDayにCompletePlanを追加する方法を知りたいです。(※PlanとCompletePlanはした量(didAmount)や名前(todoName)など情報を共有しているので、絶対Planから追加するとします。)

該当のソースコード

public class Main{ static public void main(String[] args){ new Schedule(); } } class Schedule{ public Day[] days; public Schedule(){ days = new Day[365]; //365日生成 for(int i = 365;i > 0;i--){ days[i] = new Day(i); } } } class Day{ public ArrayList<Plan> plans; public ArrayList<CompletePlan> completePlans;//日ごとに格納 public int date; public Day(int date){ this.date = date } //ユーザーからの入力の関数から呼ばれる(actionPerformed()とか) public void AddPlan(String name, int willDoAmount){ plans.add(new Plan(name, willDoAmount); } public void ShowPlans(){ //プランを表示 } public void ShowCompletePlans(){ //完了したプランを表示 } public void AddCompletePlan(CompletePlan comp){ completePlans.add(comp); } } class Plan{ public String todoName; public int willDoAmount; public ArrayList<CompletePlan> completes;//プランごとに格納  //↑このデータは構造は違えど同じデータが格納されているのが気になります public Plan(String todoName, int willDoAmount){ this.todoName = todoName; } //ユーザーからの入力の関数から呼ばれる(actionPerformed()とか) public void AddCompletePlan(int date, int amount){ //ここで、DayにCompletePlanを追加したいが、取得方法がわからない completes.add(new CompletePlan(amount, this.name)); } //リストにあるCompletePlanからdidAmountの総数から完了したかどうか算出します public boolean isComplete(){ int didAmount = 0; for(CompletePlan comp : completes){ didAmount += comp.didAmount; } if(didAmount >= willDoAmount){ return true; } return false; } } class CompletePlan{ String todoName; int didAmount; public CompletePlan(int didAmount, String todoName){ this.todoName = todoName; this.didAmount = didAmount; } }

試したこと

これに対して、2つ方法を考えました。

1.Dayを生成するときに、一緒に引数として、Scheduleも入れてアクセスできるようにする
2.ScheduleSystemのようなクラスを作って、Scheduleを格納しておく。(Scheduleは一回しか作らない)

この2つを考えたのですが、1は依存関係が循環してしまいそうで、2は回りくどくて効率的ではないと思うので、どちらも適切だとは思えないのです。

どうか、どんなことでも良いので、なにかヒントを頂ければ幸いです。

補足情報(FW/ツールのバージョンなど)

今はJavaを学習している途中です。独学なため、他の人のソースも、例題みたいなもの以外見たことがないので、これであっているのかよくわからない次第です。

###修正・補足
助言を頂き、ありがとうございました

しかし、質問するときに、コードを省いてしまった点や説明不足の点がありました。

まず、CompletePlanはPlanから生成します。(Dayから生成すると、Planに格納ができなくなると思います。なぜなら、Planの日付とCompletePlanの日付が違う場合があるからです。予定の日と同じ日するとは限りません。)

また、CompletePlanを改めてクラスとして作ったのは(初めはisCompleteで作っていたのですが)何回かに分けて予定を実行する事を考えたからです。

以上の点が抜けていました。説明が下手で、すみませんでした。

###追加質問
このようにクラスを作ると、

1.DayでCompletePlanを生成すると、Planに格納できなくなる
2.PlanでCompletePlanを生成すると、Dayを取得できなくなる
(※予定の日と完了した日は異なる場合があります)
3.DayにもPlanにもCompletePlanを格納してしまっている

という問題が出てきてしまいました。

これを解決する方法がありましたら、ご教授願います。
もしくは、根本的なことから間違っていますでしょうか。
汚いコードですみません。

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

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

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

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

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

m.ts10806

2019/10/30 14:52

>public Main{ これ本当にこう書いてますか?class Main{}ではありませんか? また、コードブロックは任意数設置できますので1つにすべて入れるよりファイル毎にわけてもらったほうが良いです。
rimokonTenko_mo

2019/10/30 15:16

そうでした。忘れてました。 このソースは、質問に何か例があればなと思ってその場で書いたものです。 何もチェックせずに書いたので、間違ってしまいました。 ご注意ありがとうございました。
swordone

2019/10/30 15:39

いや、質問編集しなよ
Zuishin

2019/11/01 00:47 編集

回答に書こうかと思いましたが、少し内容が高度かもしれないので、参考程度にここに書きます。 私なら Day に Plan も CompletePlan も持たせません。 Plan に期間を作り、Plan を集めた Plans コレクションを作ります。 Day にアクセスした場合、Day は Plans コレクションに問い合わせ、自分に関連のある Plan を抽出します。 Plans コレクションは内部に平衡二分探索木を二つ持ち、片方は Plan の開始日時をキーに、もう片方は終了日時をキーに構築します。これを使って、Day に関連する Plan を高速に検索します。 問い合わせ結果はキャッシュし、Plans コレクションの再構築で破棄するようにすれば更なる高速化が見込めるのではないかと思いますが、Plan の数が数万ほどであればその必要もないでしょう。
Zuishin

2019/11/01 00:55

と思ったけど、よく考えると、この方法だとあまり効率よく探索できませんね。一日以内に終わる予定がほとんどだと思うので、探索方法については一日以内に終わる予定とそれ以外を分けることで、もっと良い方法がありそうです。
rimokonTenko_mo

2019/11/01 09:55 編集

効率がいいかどうかはわかりませんが、結構いい方法だと思いました。質問する前に、Dayがアクセスできるようにしようと考えていましたが、毎回全部探索するのは非効率かなと思ったので、他の方法を探していました。平衡二分探索木を使えば、いける気がします。ありがとうございました。参考にさせていただきます。
guest

回答2

0

ベストアンサー

依存関係を無くすということは, 各クラスの役割や立場を明確にすることだと思います.
それは, 『依存関係を無くせば役割や立場が明確になる』のではなく, 『依存関係を無くすためには役割や立場を明確にしなければならない』と言うことです.

選手に命令することが出来るのは監督だけ…という関係にするのでしたら, 選手同士で命令しあえなくするのは当然です.
「いや, 選手同士でもやり取り出来る必要がある」というのであれば, そのような関係に設計すればいいだけです.

サンプルとしてご提示のコードですが, Plan と CompletePlan は何も共有していません.
また, Day,Plan,CompletePlan 各クラスがどう使われ, Plan.Complete() メソッドがどのようなタイミングで呼ばれるのかも分かりません.
Day が Plan と date を持って(関係付けて)いるのに, 何故 Complete メソッドは引数に date を貰うのでしょう.
そもそも予定が完了したことを別クラスとして表す必要があるのでしょうか. 単に Plan に boolean isComplete フィールドがあれば良いだけということはありませんか.

依存関係を無くす事には, 不要なクラスを無くすこともあります. クラス間の構造だけで判断せず, クラス自体の構造からお考えになると良いのではと思います。

投稿2019/10/30 18:30

jimbe

総合スコア13202

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

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

rimokonTenko_mo

2019/11/01 08:55

クラス同士の関係について、少し理解が深まりました。これからは、予めよくクラスの役割を考えて、プログラムを書こうと思います。ありがとうございます。
guest

0

クラスの分け方とかデータの持ち方が気になるのはいったん置いといて、
やりたいこと(と思われること)を実現するには、下記のような順で書くのかなと思います。

  • public void Complete(int date) このメソッドで new した CompletePlanreturn で返して
  • 呼びもとは Day クラスだと思うので、返ってきた CompletePlandate をセットする
  • それを completePlan 配列に足す

質問文の上の方にある「監督」の例については、
選手同士で命令させず、すべて監督に指示させる。
選手が他の選手に何かしてほしかったら、監督に言う。
という構造にするほうがシンプルに行けるのではないかなと思います。

または、各選手が共通の情報を見て行動し、
他の選手に伝えたいことは、共通の情報を更新する。とかでしょうか。
この場合も、選手同士の直接のやり取りは無い状態。

投稿2019/10/30 15:52

編集2019/10/30 16:09
tanishi_a

総合スコア484

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問