回答編集履歴

1

説明をやり直します。

2016/09/29 15:34

投稿

退会済みユーザー
test CHANGED
@@ -25,3 +25,287 @@
25
25
 
26
26
 
27
27
  時間があれば、サンプルコードを掲載します。
28
+
29
+
30
+
31
+ ###やり直し(追記)
32
+
33
+
34
+
35
+ ・使用処理にはポリモーフィズムが働く。ジェネリックな型に派生型のインスタンスを動的に代入できる。ポリモーフィズムは仕様変更に強い。
36
+
37
+
38
+
39
+ ・生成処理はnewを直接記述するためクラスどうしが強く結合する。利用者が、ポリモーフィズムを働かせるために、サブクラスを使おうとすれば、自分でnewを書き換えなければならない。これは、ポリモーフィズムなど使わず、直接サブクラスを使うことと変わらない。
40
+
41
+
42
+
43
+ 使用処理と生成処理を同じコードに書くと、ポリモーフィズムを使いたいのに自ら使えなくしていることになる。仕様変更の都度、生成コードを書き換えなければならず、仕様変更に弱い。
44
+
45
+
46
+
47
+ ###ファクトリ(追記)
48
+
49
+  ファクトリの目的は、newによるクラスの強い結合をなくしてクラスの独立性を確保することです。そして、凝集度を強めます。凝集度とは密接に関連するクラス間でだけnewを使用してそれを外部に公開しないことです。凝集度とはカプセル化した内部的な結合度のことです。生成処理の弱点を克服します。
50
+
51
+
52
+
53
+  外部から自由にnewさせない方法にはどんなものがあるのか。Singletonパターンは、コンストラクタをprivateにして外からインスタンスをnewできなくします。
54
+
55
+
56
+
57
+  ファクトリを使う例を示します。二項演算を表す抽象クラスArithmeticOperationを定義します。公開する抽象メソッドは二項演算を行うint calculate(int value1, int value2)ただ一つ。
58
+
59
+
60
+
61
+ ```Java
62
+
63
+ /**
64
+
65
+ * 二項演算を定義する。
66
+
67
+ */
68
+
69
+ public abstract class ArithmeticOperation {
70
+
71
+
72
+
73
+ private ArithmeticOperation() {super();}
74
+
75
+
76
+
77
+ /**
78
+
79
+ * 二項演算を実行する。
80
+
81
+ * @param value1 数値1
82
+
83
+ * @param value2 数値2
84
+
85
+ * @return 二項演算の結果を返す。
86
+
87
+ */
88
+
89
+ public abstract int calculate(int value1, int value2);
90
+
91
+
92
+
93
+ ```
94
+
95
+  抽象クラスの実現をインナークラスにします。インナークラスは、加算、減算、乗算、除算の4種類を用意。privateなクラスなので外部からは見えず、インスタンス化もできません。インスタンス化できるのは、抽象クラスArithmeticOperation、またはインナークラス自身です。
96
+
97
+
98
+
99
+ ```Java
100
+
101
+ /**
102
+
103
+ * 加算を定義する。
104
+
105
+ */
106
+
107
+ private static class Add extends ArithmeticOperation {
108
+
109
+ private Add() {super();}
110
+
111
+ public int calculate(int value1, int value2) {
112
+
113
+ return (value1 + value2);
114
+
115
+ }
116
+
117
+ }
118
+
119
+
120
+
121
+ /**
122
+
123
+ * 減算を定義する。
124
+
125
+ */
126
+
127
+ private static class Sub extends ArithmeticOperation {
128
+
129
+ private Sub() {super();}
130
+
131
+ public int calculate(int value1, int value2) {
132
+
133
+ return (value1 - value2);
134
+
135
+ }
136
+
137
+ }
138
+
139
+
140
+
141
+ /**
142
+
143
+ * 乗算を定義する。
144
+
145
+ */
146
+
147
+ private static class Mul extends ArithmeticOperation {
148
+
149
+ private Mul() {super();}
150
+
151
+ public int calculate(int value1, int value2) {
152
+
153
+ return (value1 * value2);
154
+
155
+ }
156
+
157
+ }
158
+
159
+
160
+
161
+ /**
162
+
163
+ * 除算を定義する。
164
+
165
+ */
166
+
167
+ private static class Div extends ArithmeticOperation {
168
+
169
+ private Div() {super();}
170
+
171
+ public int calculate(int value1, int value2) {
172
+
173
+ return (value1 / value2);
174
+
175
+ }
176
+
177
+ }
178
+
179
+ ```
180
+
181
+
182
+
183
+ 最後にstaticなファクトリ機能を用意します。
184
+
185
+
186
+
187
+ ```Java
188
+
189
+ /**
190
+
191
+ * Operator(二項演算)のインスタンスを取得する。
192
+
193
+ * @param operator 二項演算記号
194
+
195
+ * @return Operator(二項演算)のインスタンス
196
+
197
+ */
198
+
199
+ public static ArithmeticOperation getInstance(String operator) {
200
+
201
+ if (operator == null) {
202
+
203
+ throw new IllegalArgumentException();
204
+
205
+ }
206
+
207
+ ArithmeticOperation result = null;
208
+
209
+ switch (operator) {
210
+
211
+ case "add":
212
+
213
+ result = new ArithmeticOperation.Add();
214
+
215
+ break;
216
+
217
+ case "sub":
218
+
219
+ result = new ArithmeticOperation.Sub();
220
+
221
+ break;
222
+
223
+ case "mul":
224
+
225
+ result = new ArithmeticOperation.Mul();
226
+
227
+ break;
228
+
229
+ case "div":
230
+
231
+ result = new ArithmeticOperation.Div();
232
+
233
+ break;
234
+
235
+ default:
236
+
237
+ throw new IllegalArgumentException();
238
+
239
+ }
240
+
241
+ return result;
242
+
243
+ }
244
+
245
+ }
246
+
247
+
248
+
249
+ ```
250
+
251
+
252
+
253
+  ファクトリは文字列を受け取るパラメトリックファクトリです。引数の加減乗除の文字列に応じて二項演算クラスのインスタンスを返します。利用者クラスとの結合度は弱まります。例えば、新しい二項演算が必要なら、新しいクラスを定義してファクトリを変更すれば良いだけ。インスタンス生成のコストが高くつくなら、内部の実装をシングルトンにできます。利用者クラスの変更は必要ありません。
254
+
255
+
256
+
257
+ 利用者のコードです。
258
+
259
+
260
+
261
+ ```Java
262
+
263
+ ArithmeticOperation o = null;
264
+
265
+ int result = 0;
266
+
267
+
268
+
269
+ o = ArithmeticOperation.getInstance("add"); // ファクトリ
270
+
271
+ result = o.calculate(10, 20); // ポリモーフィズム
272
+
273
+ System.out.println("10 + 20 = "+ result);
274
+
275
+
276
+
277
+ o = ArithmeticOperation.getInstance("sub");
278
+
279
+ result = o.calculate(10, 20);
280
+
281
+ System.out.println("10 - 20 = "+ result);
282
+
283
+
284
+
285
+ o = ArithmeticOperation.getInstance("mul");
286
+
287
+ result = o.calculate(10, 20);
288
+
289
+ System.out.println("10 x 20 = "+ result);
290
+
291
+
292
+
293
+ o = ArithmeticOperation.getInstance("div");
294
+
295
+ result = o.calculate(10, 20);
296
+
297
+ System.out.println("10 / 20 = "+ result);
298
+
299
+ ```
300
+
301
+
302
+
303
+ ポリモーフィズムとファクトリはセットで使う。フレームワーク担当者はそう考えます。
304
+
305
+
306
+
307
+  最後に、あるパッケージを設計する際に、インターフェイスとファクトリだけを外部に公開する。インスタンスの生成はファクトリが隠蔽します。また実装の詳細もパッケージ内に隠蔽します。結合度を弱めることができ、必要なら実装を柔軟に変更できる良い設計ですね。
308
+
309
+
310
+
311
+  それから、生成のパターンとしてDI (Dependency Injection)があります。興味があれば調べてみてください。