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

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

詳細はこちら
Java

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

Q&A

解決済

4回答

953閲覧

同じ値を持つインスタンスを二重に作れないようにするには?

yusei_039

総合スコア6

Java

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

0グッド

0クリップ

投稿2021/03/08 12:45

編集2021/03/08 12:47

現在「わかりやすいJava オブジェクト指向 徹底解説」というテキストを読んでいます。
53ページに次のような文章がありました。

コンストラクタをprivateにするのは、インスタンスの生成をコントロールするための特殊なケースです。インスタンスを1つだけしか作れないようにするとか、同じ値を持つインスタンスを二重に作れないようにする、などの場合があります。

前者のインスタンスを1つだけしか作れないようにするというのはSingletonのことだろうというのはわかりました。

ここでいくつか質問があります。
後者の「同じ値を持つインスタンスを二重に作れないようにする」という部分にはSingletonのような名前はありますか?
また、これを効率よく実現するにはどのようにcodingすれば良いですか?

一応、実現の仕方については次のように考えてみましたが、これではインスタンスを多く作ろうとする時に大変効率が悪いように感じます。
そもそも間違っている、こうすれば効率がよい、などなど何かアドバイスがあればご教授願いたいです。よろしくお願い致します。


import java.util.LinkedList; import java.util.List; import java.util.Objects; public class Student { private int number; private String name; private static List<Student> list = new LinkedList<>(); private Student(int number, String name) { this.number = number; this.name = name; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Student)) return false; Student student = (Student) o; return number == student.number && Objects.equals(name, student.name); } @Override public int hashCode() { return Objects.hash(number, name); } public static Student getInstance(int number, String name) { Student tmp = new Student(number, name); if (list.stream() .filter(s -> s.equals(tmp)) .count() > 0) { System.out.println("すでに作成されたインスタンスです"); return null; } else { System.out.println("インスタンスの作成に成功!"); list.add(tmp); return tmp; } } }
public class Exec { public static void main(String[] args) { Student s1 = Student.getInstance(100, "佐藤一郎"); Student s2 = Student.getInstance(101, "山田花子"); Student s3 = Student.getInstance(102, "山田花子"); Student s4 = Student.getInstance(100, "佐藤一郎"); } }

実行結果
インスタンスの作成に成功!
インスタンスの作成に成功!
インスタンスの作成に成功!
すでに作成されたインスタンスです

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

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

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

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

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

guest

回答4

0

一応、実現の仕方については次のように考えてみましたが、これではインスタンスを多く作ろうとする時に大変効率が悪いように感じます。

そもそも間違っている、こうすれば効率がよい、などなど何かアドバイスがあればご教授願いたいです。

間違っているというか、そもそもそのようなことをさせたくないので、コンストラクタを呼べなくしているのに、インスタンスを生成できるようにしたら意味がありません。

ガードをかけるという実装もあるとは思いますが。
以下のようなものが意味合いとしては正しいかと思います。

java

1public class Coin { 2 private String face; 3 public final static Coin HEAD = new Coin("HEAD"); 4 public final static Coin TAIL = new Coin("TAIL"); 5 6 private Coin(String s) { 7 face = s; 8 } 9 10 public String toString() { 11 return face; 12 } 13}

あとは、DBまわりのコネクションプールとかもそうですね。
コネクション数には限りがあるので、それを自前で生成させずにコネクションを管理するクラスを
経由することでコネクションの生成に制限をつけます。

投稿2021/03/09 01:03

編集2021/03/09 02:51
momon-ga

総合スコア4826

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

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

swordone

2021/03/09 02:44

> 間違っているというか、そもそもそのようなことをさせたくないので、コンストラクタを呼べなくしているのに、インスタンスを生成できるようにしたら意味がありません。 いや、それは違うと思います。 Optionalなんかはコンストラクタはprivateですが、普通にインスタンスを作成して使います。
momon-ga

2021/03/09 05:00 編集

インスタンスを作らないということがいいたいのでなく、大量にインスタンスを作るようなものに適用しないといいたかったのです。 ※とはいえ、ぜんぜん言葉足らずですね。申し訳ないです。 Optionalと、提示にあるStudentが同じような用法で使われてるとは思いません。 > インスタンスを1つだけしか作れないようにするとか、同じ値を持つインスタンスを二重に作れないようにする Optionalは、どちらの例にも当てはまらないと思います。そもそも、Optionl自体は意味のあるエンティティじゃないので・・・
swordone

2021/03/18 14:59

では、LocalDateTimeなどはどうでしょう?
momon-ga

2021/03/19 00:50 編集

LocalDateTImeが > コンストラクタをprivateにするのは、インスタンスの生成をコントロールするための特殊なケースです。インスタンスを1つだけしか作れないようにするとか、同じ値を持つインスタンスを二重に作れないようにする、などの場合があります。 を実現している例とは思えないですけど、どうでしょうか? インスタンスを生成するメソッドを公開すれば、コンストラクタをprivateにしても、インスタンスは複数作れるのは当然ですし、探せば他にもでてくると思います。 コンストラクタをprivateにする意味もほぼないです。インスタンス生成に名前をつけることを目的としているのだと思います。 上記の例と違う理由で、コンストラクタをprivateにすることもあるという主張でしたら、否定はしません。
swordone

2021/03/19 02:02

「インスタンスの生成をコントロール」には当てはまるのではないでしょうか。この説明は「インスタンスの生成をコントロールする」例は言ってますが、「コンストラクタをprivateにするケースは必ずこれだ」とは言っていません。
momon-ga

2021/03/19 05:43

おっしゃるとおりですね。< コンストラクタをprivateにするケースは必ずこれだ」とは言っていません。
guest

0

名前は知りませんが、少なくとも作成済みのインスタンスの保存はSetにするべきでしょう。Listの場合は毎回端から順番に探すことになり、効率が悪いです。

投稿2021/03/08 12:59

swordone

総合スコア20669

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

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

dodox86

2021/03/08 13:55

>@質問者さん Singletonは「デザインパターン」の中で述べられるパターンの名前のひとつで、同じ値を持つインスタンスを複数持たせないというパターンは「デザインパターン」の中には特に無いので、そのレベルでは「無い」と言えるのではないでしょうか。「データ構造」としてみると、値に重複が無いものはswordoneさんの回答の「Set」がそのものズバリで言えていると思います。「Set」とは、Java以外の他のプログラミング言語でも使われますし。 Set (abstract data type) https://en.wikipedia.org/wiki/Set_(abstract_data_type)
guest

0

ベストアンサー

このようなパターンでは、前提として、返されるインスタンスの値は、変更不可である必要があります。
目的は、他の方も指摘されておりますが、リソースの節約でしょうか。

呼ぶ側のニーズを考えると、既存のインスタンスがあれば、それを返すようにしないと、早いもの勝ちとなるので、システムが組めないかと。

速度の改善ですが、Listではなく、Mapを多重にすれば、それなりには改善するかと。

なお、クラス全体ではないですが、java.lang.StringのvalueOf()が、同じような考え方で実装されているかと思います。

投稿2021/03/09 09:32

YT0014

総合スコア1748

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

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

0

質問後半とは目的が違いますが、機構・構造はFlyweight パターンと同じかと思います。

https://ja.wikipedia.org/wiki/Flyweight パターン

等価なインスタンスを別々の箇所で使用する際に、一つのインスタンスを再利用することによってプログラムを省リソース化することを目的とする。

その時点で対象のインスタンスが生成されていない場合

  1. 対象のインスタンスを新たに生成する。
  2. 生成したインスタンスをプールする(言い換えると、メンバのコンテナオブジェクトに格納する)。
  3. 生成されたインスタンスを返す。

対象のインスタンスが既に生成されていた場合

  1. 対象のインスタンスをプールから呼び出す。
  2. 対象のインスタンスを返す。

その本を参照できないので判断できませんが、元の文がFlyweight パターンについて説明していて、それに対して目的を誤読している可能性もありそうです。

投稿2021/03/08 14:10

編集2021/03/08 14:11
quickquip

総合スコア11231

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問