SlideShare a Scribd company logo
1 of 34
Download to read offline
Effective Java
Second Edition

社内勉強会資料

第4章 Classes and Interfaces

大槌 剛彦 (@ohtsuchi)
項目13 クラスとメンバーへのアクセス可能性を最小限にする
• 情報隠蔽(information hiding) or カプセル化(encapsulation)
–
–
–
–

他のモジュールから内部の実装を隠蔽
実装とAPIを分離
APIを通して他のモジュールと通信
利点
• モジュールの並行開発→ 開発スピードのUP
• メンテナンスの負担緩和

• アクセス可能性(accessibility)を決定するアクセス制御 (access control)
– 宣言された場所 と、
– アクセス修飾子(private, protected, and public) で決まる
– 目安
• できるだけアクセスできないように
項目13 クラスとメンバーへのアクセス可能性を最小限にする
• トップレベル(ネストしていない)クラス・インタフェース
– 2種類のアクセスレベル

• package-private
• public
– 可能ならば package-private にする

– public : 互換性を維持するために永久にサポートする義務。APIの一部。
– package-private top-level class を1つのクラスだけが使用している場合
• その使用している1つのクラスの private nested class にする事を検討

• メンバー(field, method, nested class, nested interface)
– 4種類のアクセスレベル

•
•
•
•
–

private
package-private
protected
Public

できるだけ全てのメンバーをprivateにする
項目13 クラスとメンバーへのアクセス可能性を最小限にする
• Serializable を実装している場合
– private と package-private のメンバーであっても公開API の中に leak してしまう(項目74 )
• 古いバージョンでシリアライズ
• → 内部表現を変更
• → 新しいバージョンでデシリアライズ
• → プログラム失敗

• メソッドをオーバライド
– サブクラスでアクセスレベルを低くできない

• インタフェースにあるメソッド
– 全てpublic

• テストを容易にするために
– private → package-private まで緩和するのは受け入れられる
項目13 クラスとメンバーへのアクセス可能性を最小限にする
• インスタンスフィールド:public にすべきではない → 項目14
– 以下の事を放棄することになる
• そのフィールドに保存できる値を制限
• そのフィールドに関係する不変式(invariant)を強制
• そのフィールドが変更された時に何らかの補助処理を行う
– 例外

• public static final の定数 は公開してよい(定数)
– 基本データ型
– 不変オブジェクト(項目15)への参照
– finalの可変オブジェクトの参照は?
» 参照は変更できないが、参照されているオブジェクトは操作できる
» 悲惨な結果になる変更が可能
» (例)長さが0ではない配列 → 可変

// Potential security hole!
public static final Thing[] VALUES = { ... };
項目13 クラスとメンバーへのアクセス可能性を最小限にする
• public static final の配列の修正:2通りの解決
– publicの不変リスト
private static final Thing[] PRIVATE_VALUES = { ... };
public static final List<Thing> VALUES =
Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));

– 配列のコピーを返すpublicのメソッド
private static final Thing[] PRIVATE_VALUES = { ... };
public static final Thing[] values() {
return PRIVATE_VALUES.clone();
}
項目14 public のクラスでは、
publicのフィールドではなく、アクセッサーメソッドを使う

• public の accessor method (getter) と
• 可変クラスに対するmutator (setter)
class Point {
private double x;
private double y;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() { return x; }
public double getY() { return y; }
public void setX(double x) { this.x = x; }
public void setY(double y) { this.y = y; }
}

– accessor method の提供
• クラス内部の表現形式を変更する柔軟性を保つ
項目15 可変性を最小限にする
• 不変クラスにするための5つの規則
– 1. 状態を変更するメソッド(= mutator) を提供しない

– 2. クラスが拡張できない事を保証する
• → サブクラスに状態を変更されないように
– 3. 全てのフィールドをfinalにする
– 4. 全てのフィールドをprivateにする
– 5. 可変コンポーネントに対する exclusive access を保証する
• 可変オブジェクトを参照しているフィールドを持っている場合:
– クライアントがそのオブジェクトへの参照を取得できないように
– クライアントが提供したオブジェクト参照で初期化してはいけない
– accessor からオブジェクトの参照を返してはいけない
– defensive copy をする
» コンストラクタ
» Accessor
» readObject (項目76)
項目15 可変性を最小限にする
// 複素数を表すクラス
public finalclass Complex {
private final double re;
private final double im;
public Complex(double re, double im) {
this.re = re;
this.im = im;
}
// 実数部分・虚数部分へのアクセサーを提供
// アクセサー のみ (対応する mutator を持たない)
public double realPart() { return re; }
public double imaginaryPart() { return im; }

// 4つの算術操作:足し算・引き算・掛け算・割り算を提供
public Complex add(Complex c) {
return new Complex(re + c.re, im + c.im);
}
(…以下省略)

•

新たなインスタンスを生成して返している (算術操作メソッドの部分)
– 関数的方法
• オペランドを変更することなく、関数を適用した結果を返す
項目15 可変性を最小限にする
• 不変オブジェクト
– スレッドセーフ。同期を必要としない。
– 制限なく共有できる
• コピー(#cloneやコピーコンストラクタ)を行う必要が無い
– コピー元と同値なので
– 既存のクラスを再利用
• 頻繁に使用される値 → 定数を提供
public static final Complex ZERO = new Complex(0, 0);
public static final Complex ONE = new Complex(1, 0);
public static final Complex I = new Complex(0, 1);

– 頻繁に要求されるインスタンスをキャッシュするstatic ファクトリメソッドを提供できる(項目1)
–

内部も共有できる

• 【例】 BigInteger の negate メソッド
– 同じ大きさで反対の符号のBigIntegerを返す
– 大きさ=int[] をコピーする必要がない
public class BigInteger extends Number … {
final int signum; // -1 for negative, 0 for zero, or 1 for positive
final int[] mag;
…

public BigInteger negate() {
return new BigInteger(this.mag, -this.signum);
項目15 可変性を最小限にする
• 不変オブジェクトの欠点
– 異なる値に対して、別々のオブジェクトが必要
– オブジェクトが大きい場合
• コストが高くつく

– (例) BigInteger で 100万ビットのデータの最下位ビットを反転
» 元のインスタンスと1ビットしか違わないのに
» → 100万ビットの新たなBigIntegerインスタンスを生成→ 生成コスト高
– Bitset(可変)の場合
» 最下位ビットの1ビットの状態を変更 → 一定時間で可能

– 複数ステップの処理
• 各ステップで新たなオブジェクトを生成 → 最終結果以外の全てのオブジェクトを破棄
→ パフォーマンスの問題
• 対処法2つ
– 複数ステップを1つの操作で提供する

– public の可変 companion class を提供する
» (主な例)StringとStringBuilder
» (ある状況では)BigInteger と Bitsetもその関係
項目15 可変性を最小限にする
• 不変オブジェクトの設計
– 不変性を保証するために、サブクラス化の禁止
• 方法1: class を final にする
• 方法2: コンストラクタを全て private or package-private にして、public static factory(項目
1)を追加
// コンストラクタの代わりに、 static factoryを持つ不変クラス
public class Complex {
private final double re;
private final double im;
private Complex(double re, double im) {
this.re = re;
this.im = im;
}
public static Complex valueOf(double re, double im){
return new Complex(re, im);
}
...
}

• static factoryの利点:
– Flexible
» 後からキャッシュ機能を追加したり

– 名前が明確 (例: #valueOf と #valueOfPolar)
» コンストラクタだけの場合、別の生成手段で、同じシグニチャになってしまう事がある
項目15 可変性を最小限にする
• 不変オブジェクト:まとめ
– できるだけクラスは不変にする
• 特に小さなオブジェクトは常に不変にすべき
• 大きなオブジェクトも不変にすることを検討

– パフォーマンスを得るために必要な時だけ、
public の可変 companion class を提供
– クラスを不変にできない場合
• その可変性をできるだけ制限

– 理由がない限り、全てのフィールドをfinalにする
• コストが高い計算結果(例: hashCode計算)をキャッシュするために 、
finalでない冗長なフィールドを持つ場合あり。
– → String でも使用されている
項目16 継承よりコンポジションを選ぶ
• 継承はカプセル化を破る
– Superclassの実装詳細に依存
• 後から superclass の実装が変更されたら、subclassが機能しなくなる可能性
// 継承の不適切な利用
public class InstrumentedHashSet<E> extends HashSet<E> {
// 要素の挿入回数
private int addCount = 0;
…
@Override public boolean add(E e) {
addCount++;
return super.add(e);
}
@Override public boolean addAll(Collection<? extends E> c) {
addCount += c.size();
return super.addAll(c);
}
public int getAddCount() {
return addCount;
}
}

InstrumentedHashSet<String> s = new InstrumentedHashSet<String>();
s.addAll(Arrays.asList("Snap", "Crackle", "Pop"));
項目16 継承よりコンポジションを選ぶ
•

ニ重にカウントされる

– getAddCount → 3ではなく6が返ってくる
– HashSet#addAll (AbstractCollection#addAll)は内部で #add を使用しているため
– 修理する事もできるが、、、、
• #addAll の Override を止める or
– HashSet#addAll が #addを使用して実装されている事実に依存
» → 自己利用 “self-use”
• Javaプラットフォームの全ての実装で行われている保証はない
• リリースごとに変更される可能性

• #addAll の中で 要素をiterateして #add 呼び出し
– HashSet#addAll を呼び出さない
» → superclass のメソッドを再実装するのに等しい
項目16 継承よりコンポジションを選ぶ
• Composition
– 既存クラスを extend する代わりに、 既存クラスを private field にする。
– 新クラスのインスタンスメソッド
• 既存クラスの対応するメソッドを呼ぶ
• forwarding method と呼ばれる
// Wrapper class - 継承の代わりに composition を使用
public class InstrumentedSet<E> extends ForwardingSet<E> {
private int addCount = 0;
public InstrumentedSet(Set<E> s) {
super(s);
}
…

}
// 再利用可能な forwarding class
public class ForwardingSet<E> implements Set<E> {
private final Set<E> s;
public ForwardingSet(Set<E> s) { this.s = s; }
…

public boolean add(E e) { return s.add(e); }
…

public boolean addAll(Collection<? extends E> c)
{ return s.addAll(c); }
…

}
項目16 継承よりコンポジションを選ぶ
• InstrumentedSet は 他のSetインスタンスをラップする
– wrapper class とも呼ばれる
– Decorator pattern
Set<Date> s = new InstrumentedSet<Date>(new TreeSet<Date>(cmp));
Set<E> s2 = new InstrumentedSet<E>(new HashSet<E>(capacity));

– 既に使用されているSetインスタンスを一時的に計測
static void walk(Set<Dog> dogs) {
InstrumentedSet<Dog> iDogs = new InstrumentedSet<Dog>(dogs);
// このメソッド内では、dogsの代わりに、iDogsを使用
}

• 委譲(delegation) != (composition と forwarding の組み合わせ)
– wrapper object が自分自身を wrapped object へ渡さない限り、委譲ではない
項目16 継承よりコンポジションを選ぶ
• 継承が適切の場合
– 本当のサブタイプ関係がある場合だけ
– クラスBは、クラスAとの間に「is-a」関係が存在している場合のみ、クラスA
を拡張
• 「全てのBは本当にAであるか」

– javaのライブラリで原則を破っている例
• Stack (extends Vector)
• Properties (extends Hashtable)
• → どちらの場合も composition にするほうが適切だった
項目17 継承のために設計および文章化する、
でなければ継承を禁止する
• [オーバライド可能なメソッド]を呼び出すメソッド
– 呼び出しに関する記述は「This implementation」で始まる
public abstract class AbstractCollection<E> implements Collection<E> {
…
public abstract Iterator<E> iterator();
…
/**
* {@inheritDoc}
*
* <p>This implementation iterates over the collection looking for the
* specified element. If it finds the element, it removes the element
* from the collection using the iterator's remove method.
*
*…
*/
public boolean remove(Object o) {
Iterator<E> it = iterator();
if (o==null) {
…

– #iterator をオーバライドすることによって、#remove に影響を与える事が
記述されている
項目17 継承のために設計および文章化する、
でなければ継承を禁止する
• 継承のために設計されたクラス
– →サブクラスを書いてテスト
• 継承を可能にするための制約
– コンストラクタは、オーバライド可能なメソッドを呼び出してはいけない
public class Super {
// コンストラクタがオーバライド可能なメソッドを呼び出し

public Super() {
overrideMe();
}
public void overrideMe() {}
}
public final class Sub extends Super {
private final Date date; // Blank final, set by constructor
Sub() { date = new Date();} // コンストラクタ
@Override public void overrideMe() {
System.out.println(date);
}
public static void main(String[] args) {

Sub sub = new Sub();
sub.overrideMe();
}

}
項目17 継承のために設計および文章化する、
でなければ継承を禁止する
•

実行結果例
null
Tue Feb 04 11:01:18 JST 2014

• Cloneable または Serializable する場合にもコンストラクタと似た振る舞い
– #clone
– #readObject
– 上記メソッドからオーバライド可能なメソッドを呼び出してはいけない

• 文書化されていないクラスのサブクラス化の禁止
– 方法1:クラスをfinal にする
– 方法2:コンストラクタを全て private or package-private にして 、public static factory を提供
項目18 abstract class よりも interface を選ぶ
• abstract class
– メソッドの実装を含む

• Interface
– メソッドの実装を含まない
• (※)java8 では default 実装を定義できるそうですが…

• javaは単一継承のみ
– クラスは2つ以上の親は持てない
– 2つのクラスに同じ抽象クラスを拡張させたければ
→ 高い位置(両方のクラスの先祖) に定義する必要あり
項目18 abstract class よりも interface を選ぶ
• Interface
– mixin を定義するのに理想的
– 階層を持たない型
public interface Singer {
AudioClip sing(Song s);
}
public interface Songwriter {
Song compose(boolean hit);
}

public interface SingerSongwriter extends Singer, Songwriter {
AudioClip strum();
void actSensitive();
}
項目18 abstract class よりも interface を選ぶ
• 骨格実装 (skeletal implementation)
– interface ごとに
– 実装補助を提供
– 慣例として、AbstractInterface と呼ばれる
• Collections Framework で提供している骨格実装の例
– AbstractCollection, AbstractSet, AbstractList, AbstractMap

• 骨格実装の書き方
– interface を調べる
– 基本操作を決める
• → abstract method にする

– 他の全てのメソッド
• →具体的な実装を提供
項目18 abstract class よりも interface を選ぶ
•

骨格実装の例

– int[] を List<Integer> として見せる Adapter
– static factory の中に隠蔽されている anonymous class
static List<Integer> intArrayAsList(final int[] a) {
if (a == null)
throw new NullPointerException();
return new AbstractList<Integer>() {
public Integer get(int i) {
return a[i]; // Autoboxing (Item 5)
}

@Override public Integer set(int i, Integer val) {
int oldVal = a[i];
a[i] = val; // Auto-unboxing
return oldVal; // Autoboxing
}
public int size() {
return a.length;
}
};
}
• ※パフォーマンスはそれほど良いわけではない (boxing 、unboxing をしているため)
項目18 abstract class よりも interface を選ぶ
•

Map.Entryの骨格実装例
public abstract class AbstractMapEntry<K,V> implements Map.Entry<K,V> {
// Primitive operations
public abstract K getKey();
public abstract V getValue();
// 変更可能な Mapの Entries は、このメソッドを override しなければならない
public V setValue(V value) {
throw new UnsupportedOperationException();
}
// Implements the general contract of Map.Entry.equals
@Override public boolean equals(Object o) {
if (o == this)
return true;
if (! (o instanceof Map.Entry))
return false;
Map.Entry<?,?> arg = (Map.Entry) o;
return equals(getKey(), arg.getKey()) &&
equals(getValue(), arg.getValue());
}
…
}
項目19 型を定義するためだけに interface を使用する
• interface は 型を定義するためだけに使用すべき
• 定数を提供するために使用すべきではない
– ダメな例:
• 定数インタフェース (constant interface)

• 選択肢
– 既存の class または interface に強く結びついている場合:
• その class または interface に定数を追加
– (例)数字(Integer や Floatなど)クラス の MIN_VALUE や MAX_VALUE

– 定数が列挙型のメンバーとして見なされるのがbestならば:
• enum type で定数を提供 (項目30)

– そうでなければ…
• インスタンス化不能な utility class で定数を提供
項目20 タグ付クラスよりクラス階層を選ぶ
// Tagged class - クラス階層より、かなり劣る
class Figure {
enum Shape { RECTANGLE, CIRCLE };
// Tag field - the shape of this figure
final Shape shape;
// These fields are used only if shape is RECTANGLE
double length;
double width;

// This field is used only if shape is CIRCLE
double radius;
// Constructor for circle
Figure(double radius) {
shape = Shape.CIRCLE;
this.radius = radius;
}
// Constructor for rectangle
Figure(double length, double width) {
shape = Shape.RECTANGLE;
this.length = length;
this.width = width;
}
項目20 タグ付クラスよりクラス階層を選ぶ
double area() {
switch(shape) {
case RECTANGLE:
return length * width;
case CIRCLE:
return Math.PI * (radius * radius);
default:
throw new AssertionError();
}
}
}

• 欠点
– 決まりきったコードで散らかっている
• enum 宣言
• tag field
• switch 文

– メモリ量が増加
• 他の特性に属するフィールドを抱えているため

– 特性の追加時にソースの修正が必要
• switch 文 に case を追加しなければならない
項目20 タグ付クラスよりクラス階層を選ぶ
• サブタイプ化
// クラス階層による置き換え
abstract class Figure {
abstract double area();
}
class Circle extends Figure {
final double radius;
Circle(double radius) { this.radius = radius; }
double area() { return Math.PI * (radius * radius); }
}
class Rectangle extends Figure {
final double length;
final double width;
Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
double area() { return length * width; }
}

•

各特性の実装に対して → 独自のクラスを定義
– 自分と無関係なデータフィールドを負っていない

•

全ての field が final
項目21 戦略を表現するために関数オブジェクトを使用する
• java は 関数ポインタを提供していないが、オブジェクトへの参照を使用できる
– [他のオブジェクト]に対して操作を行うメソッドを持つオブジェクトを定義
•
•
•
•

他のオブジェクトがそのメソッドに明示的に渡される
そのようなメソッドを1つだけ公開
関数オブジェクト(function object)と呼ばれる
戦略(Strategy)パターンを実装
– 戦略を表すインタフェース(Strategy interface)
public interface Comparator<T> {
public int compare(T t1, T t2);
}

– 個々の具象戦略クラス(Concrete strategy class)
class StringLengthComparator implements Comparator<String> {
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
}

» StringLengthComparatorの戦略:
• 辞書順ではなく、文字列の長さで順序付け
項目21 戦略を表現するために関数オブジェクトを使用する
• Stateless
– シングルトンにするのに適している
class StringLengthComparator {
private StringLengthComparator() { }
public static final StringLengthComparator
INSTANCE = new StringLengthComparator();

public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
}

• anonymous classで使用
Arrays.sort(stringArray, new Comparator<String>() {
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
});

– → 呼び出し毎に新たなインスタンス生成

• 繰り返し実行する場合は private static final にして再利用を検討
項目21 戦略を表現するために関数オブジェクトを使用する
• concrete strategy class は public にする必要はない
– “host class” の private nested class にできる
class Host {
private static class StrLenCmp implements Comparator<String>, Serializable {
public int compare(String s1, String s2) {
return s1.length() - s2.length();
}
}
public static final Comparator<String>
STRING_LENGTH_COMPARATOR = new StrLenCmp();
…
}

– Stringクラス の CASE_INSENSITIVE_ORDER はこのパターン
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
…
public static final Comparator<String> CASE_INSENSITIVE_ORDER
= new CaseInsensitiveComparator();
private static class CaseInsensitiveComparator
implements Comparator<String>, java.io.Serializable {
public int compare(String s1, String s2) {
…
項目22 非staticのメンバークラスより
staticのメンバークラスを選ぶ

• nested class
– 他のclass内に定義されたclass
– enclosing class に対して仕えるためだけに存在すべき
– 4種類
• static member class
• nonstatic member class
• anonymous class
• local class
• enclosing instance への参照が必要ならば nonstatic にする
• →そうでなければ、staticにする。
•

クラスがメソッド内に属していて、1箇所からのみインスタンスを生成する必要があり、
そのクラスを特徴づける型が存在すれば、anonymous class にする

More Related Content

Similar to Effective java2nd chap04

jjugccc2018 app review postmortem
jjugccc2018 app review postmortemjjugccc2018 app review postmortem
jjugccc2018 app review postmortemtamtam180
 
Effective Java 輪読会 第4章 項目13-17
Effective Java 輪読会 第4章 項目13-17Effective Java 輪読会 第4章 項目13-17
Effective Java 輪読会 第4章 項目13-17Appresso Engineering Team
 
第2回デザインパターン資料
第2回デザインパターン資料第2回デザインパターン資料
第2回デザインパターン資料gaaupp
 
基礎構文班22回目 試験対策もどき
基礎構文班22回目 試験対策もどき基礎構文班22回目 試験対策もどき
基礎構文班22回目 試験対策もどきXMLProJ2014
 
Building andobservingcloudnativeappliactionusingazure elastic-terraform
Building andobservingcloudnativeappliactionusingazure elastic-terraformBuilding andobservingcloudnativeappliactionusingazure elastic-terraform
Building andobservingcloudnativeappliactionusingazure elastic-terraformShotaro Suzuki
 
Java Just-In-Timeコンパイラ
Java Just-In-TimeコンパイラJava Just-In-Timeコンパイラ
Java Just-In-TimeコンパイラKazuaki Ishizaki
 
今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 TipsTakaaki Suzuki
 
PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!Shohei Okada
 
jQueryの先に行こう!最先端のWeb開発トレンドを学ぶ
jQueryの先に行こう!最先端のWeb開発トレンドを学ぶjQueryの先に行こう!最先端のWeb開発トレンドを学ぶ
jQueryの先に行こう!最先端のWeb開発トレンドを学ぶShumpei Shiraishi
 
Introduction to JShell: the Java REPL Tool #jjug_ccc #ccc_ab4
Introduction to JShell: the Java REPL Tool #jjug_ccc #ccc_ab4Introduction to JShell: the Java REPL Tool #jjug_ccc #ccc_ab4
Introduction to JShell: the Java REPL Tool #jjug_ccc #ccc_ab4bitter_fox
 
エキ Py 読書会02 2010/9/7
エキ Py 読書会02 2010/9/7エキ Py 読書会02 2010/9/7
エキ Py 読書会02 2010/9/7Tetsuya Morimoto
 
rpscala35-scala2.9.0
rpscala35-scala2.9.0rpscala35-scala2.9.0
rpscala35-scala2.9.0Kenji Yoshida
 
React Native GUIDE
React Native GUIDEReact Native GUIDE
React Native GUIDEdcubeio
 
Kubernetes meetup-tokyo-13-customizing-kubernetes-for-ml-cluster
Kubernetes meetup-tokyo-13-customizing-kubernetes-for-ml-clusterKubernetes meetup-tokyo-13-customizing-kubernetes-for-ml-cluster
Kubernetes meetup-tokyo-13-customizing-kubernetes-for-ml-clusterPreferred Networks
 
【アシアル塾】PHPオブジェクト指向再入門・第三回Exceptionクラスによる例外処理
【アシアル塾】PHPオブジェクト指向再入門・第三回Exceptionクラスによる例外処理【アシアル塾】PHPオブジェクト指向再入門・第三回Exceptionクラスによる例外処理
【アシアル塾】PHPオブジェクト指向再入門・第三回Exceptionクラスによる例外処理アシアル株式会社
 

Similar to Effective java2nd chap04 (20)

20180123 power shell
20180123 power shell20180123 power shell
20180123 power shell
 
jjugccc2018 app review postmortem
jjugccc2018 app review postmortemjjugccc2018 app review postmortem
jjugccc2018 app review postmortem
 
Effective Java 輪読会 第4章 項目13-17
Effective Java 輪読会 第4章 項目13-17Effective Java 輪読会 第4章 項目13-17
Effective Java 輪読会 第4章 項目13-17
 
MoteMote Compiler Plugin
MoteMote Compiler PluginMoteMote Compiler Plugin
MoteMote Compiler Plugin
 
第2回デザインパターン資料
第2回デザインパターン資料第2回デザインパターン資料
第2回デザインパターン資料
 
基礎構文班22回目 試験対策もどき
基礎構文班22回目 試験対策もどき基礎構文班22回目 試験対策もどき
基礎構文班22回目 試験対策もどき
 
Building andobservingcloudnativeappliactionusingazure elastic-terraform
Building andobservingcloudnativeappliactionusingazure elastic-terraformBuilding andobservingcloudnativeappliactionusingazure elastic-terraform
Building andobservingcloudnativeappliactionusingazure elastic-terraform
 
Java class design
Java class designJava class design
Java class design
 
Java Just-In-Timeコンパイラ
Java Just-In-TimeコンパイラJava Just-In-Timeコンパイラ
Java Just-In-Timeコンパイラ
 
Unityで覚えるC#
Unityで覚えるC#Unityで覚えるC#
Unityで覚えるC#
 
今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips
 
PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!PHP 2大 web フレームワークの徹底比較!
PHP 2大 web フレームワークの徹底比較!
 
Tdd
TddTdd
Tdd
 
jQueryの先に行こう!最先端のWeb開発トレンドを学ぶ
jQueryの先に行こう!最先端のWeb開発トレンドを学ぶjQueryの先に行こう!最先端のWeb開発トレンドを学ぶ
jQueryの先に行こう!最先端のWeb開発トレンドを学ぶ
 
Introduction to JShell: the Java REPL Tool #jjug_ccc #ccc_ab4
Introduction to JShell: the Java REPL Tool #jjug_ccc #ccc_ab4Introduction to JShell: the Java REPL Tool #jjug_ccc #ccc_ab4
Introduction to JShell: the Java REPL Tool #jjug_ccc #ccc_ab4
 
エキ Py 読書会02 2010/9/7
エキ Py 読書会02 2010/9/7エキ Py 読書会02 2010/9/7
エキ Py 読書会02 2010/9/7
 
rpscala35-scala2.9.0
rpscala35-scala2.9.0rpscala35-scala2.9.0
rpscala35-scala2.9.0
 
React Native GUIDE
React Native GUIDEReact Native GUIDE
React Native GUIDE
 
Kubernetes meetup-tokyo-13-customizing-kubernetes-for-ml-cluster
Kubernetes meetup-tokyo-13-customizing-kubernetes-for-ml-clusterKubernetes meetup-tokyo-13-customizing-kubernetes-for-ml-cluster
Kubernetes meetup-tokyo-13-customizing-kubernetes-for-ml-cluster
 
【アシアル塾】PHPオブジェクト指向再入門・第三回Exceptionクラスによる例外処理
【アシアル塾】PHPオブジェクト指向再入門・第三回Exceptionクラスによる例外処理【アシアル塾】PHPオブジェクト指向再入門・第三回Exceptionクラスによる例外処理
【アシアル塾】PHPオブジェクト指向再入門・第三回Exceptionクラスによる例外処理
 

Recently uploaded

My Inspire High Award 2024「なぜ議会への関心が低いのか?」
My Inspire High Award 2024「なぜ議会への関心が低いのか?」My Inspire High Award 2024「なぜ議会への関心が低いのか?」
My Inspire High Award 2024「なぜ議会への関心が低いのか?」inspirehighstaff03
 
International Politics I - Lecture 1
International Politics I - Lecture 1International Politics I - Lecture 1
International Politics I - Lecture 1Toru Oga
 
リアル戦国探究in米沢 当日講座1(スタッフ共有用)『兵は詐をもって立つ』についてのスライド
リアル戦国探究in米沢 当日講座1(スタッフ共有用)『兵は詐をもって立つ』についてのスライドリアル戦国探究in米沢 当日講座1(スタッフ共有用)『兵は詐をもって立つ』についてのスライド
リアル戦国探究in米沢 当日講座1(スタッフ共有用)『兵は詐をもって立つ』についてのスライドKen Fukui
 
What I did before opening my business..pdf
What I did before opening my business..pdfWhat I did before opening my business..pdf
What I did before opening my business..pdfoganekyokoi
 
リアル戦国探究in米沢 事前講座2スライド(スタッフ共有用)『両雄の強さの秘密』についてのスライド
リアル戦国探究in米沢 事前講座2スライド(スタッフ共有用)『両雄の強さの秘密』についてのスライドリアル戦国探究in米沢 事前講座2スライド(スタッフ共有用)『両雄の強さの秘密』についてのスライド
リアル戦国探究in米沢 事前講座2スライド(スタッフ共有用)『両雄の強さの秘密』についてのスライドKen Fukui
 
TEAMIN Service overview for customer_20240422.pdf
TEAMIN Service overview for customer_20240422.pdfTEAMIN Service overview for customer_20240422.pdf
TEAMIN Service overview for customer_20240422.pdfyukisuga3
 
My Inspire High Award 2024 「本当の『悪者』って何?」
My Inspire High Award 2024 「本当の『悪者』って何?」My Inspire High Award 2024 「本当の『悪者』って何?」
My Inspire High Award 2024 「本当の『悪者』って何?」inspirehighstaff03
 
My Inspire High Award 2024「Yakushima Islandってなんか変じゃない?」.pdf
My Inspire High Award 2024「Yakushima Islandってなんか変じゃない?」.pdfMy Inspire High Award 2024「Yakushima Islandってなんか変じゃない?」.pdf
My Inspire High Award 2024「Yakushima Islandってなんか変じゃない?」.pdfinspirehighstaff03
 
My Inspire High Award2024「外国人が日本のテーブルマナーに驚く理由は?」
My Inspire High Award2024「外国人が日本のテーブルマナーに驚く理由は?」My Inspire High Award2024「外国人が日本のテーブルマナーに驚く理由は?」
My Inspire High Award2024「外国人が日本のテーブルマナーに驚く理由は?」inspirehighstaff03
 
My Inspire High Award 2024「他者と自分、対立を防ぐには?」
My Inspire High Award 2024「他者と自分、対立を防ぐには?」My Inspire High Award 2024「他者と自分、対立を防ぐには?」
My Inspire High Award 2024「他者と自分、対立を防ぐには?」inspirehighstaff03
 
My Inspire High Award 2024  「正義って存在するの?」
My Inspire High Award 2024  「正義って存在するの?」My Inspire High Award 2024  「正義って存在するの?」
My Inspire High Award 2024  「正義って存在するの?」inspirehighstaff03
 
リアル戦国探究in米沢 当日講座2スライド(スタッフ共有用)『人を致すも人に致されず』についてのスライド
リアル戦国探究in米沢 当日講座2スライド(スタッフ共有用)『人を致すも人に致されず』についてのスライドリアル戦国探究in米沢 当日講座2スライド(スタッフ共有用)『人を致すも人に致されず』についてのスライド
リアル戦国探究in米沢 当日講座2スライド(スタッフ共有用)『人を致すも人に致されず』についてのスライドKen Fukui
 
リアル戦国探究in米沢 当日講座3スライド(スタッフ共有用)『糧は三度はさいせず』についてのスライド
リアル戦国探究in米沢 当日講座3スライド(スタッフ共有用)『糧は三度はさいせず』についてのスライドリアル戦国探究in米沢 当日講座3スライド(スタッフ共有用)『糧は三度はさいせず』についてのスライド
リアル戦国探究in米沢 当日講座3スライド(スタッフ共有用)『糧は三度はさいせず』についてのスライドKen Fukui
 
My Inspire High Award 2024 「AIと仲良くなるには?」
My Inspire High Award 2024 「AIと仲良くなるには?」My Inspire High Award 2024 「AIと仲良くなるには?」
My Inspire High Award 2024 「AIと仲良くなるには?」inspirehighstaff03
 
My Inspire High Award 2024      「家族とは何か」
My Inspire High Award 2024      「家族とは何か」My Inspire High Award 2024      「家族とは何か」
My Inspire High Award 2024      「家族とは何か」inspirehighstaff03
 
My Inspire High Award 2024「老いることは不幸なこと?」
My Inspire High Award 2024「老いることは不幸なこと?」My Inspire High Award 2024「老いることは不幸なこと?」
My Inspire High Award 2024「老いることは不幸なこと?」inspirehighstaff03
 
My Inspire High Award 2024「スーパーマーケットで回収されたキャベツ外葉は廃棄されているの?」
My Inspire High Award 2024「スーパーマーケットで回収されたキャベツ外葉は廃棄されているの?」My Inspire High Award 2024「スーパーマーケットで回収されたキャベツ外葉は廃棄されているの?」
My Inspire High Award 2024「スーパーマーケットで回収されたキャベツ外葉は廃棄されているの?」inspirehighstaff03
 
My Inspire High Award 2024「なぜ人は他人と違うところがあってもそれをなかなか誇れないのか?」
My Inspire High Award 2024「なぜ人は他人と違うところがあってもそれをなかなか誇れないのか?」My Inspire High Award 2024「なぜ人は他人と違うところがあってもそれをなかなか誇れないのか?」
My Inspire High Award 2024「なぜ人は他人と違うところがあってもそれをなかなか誇れないのか?」inspirehighstaff03
 
リアル戦国探究in米沢 事前講座1スライド(スタッフ共有用)『川中島の謎』についてのスライド
リアル戦国探究in米沢 事前講座1スライド(スタッフ共有用)『川中島の謎』についてのスライドリアル戦国探究in米沢 事前講座1スライド(スタッフ共有用)『川中島の謎』についてのスライド
リアル戦国探究in米沢 事前講座1スライド(スタッフ共有用)『川中島の謎』についてのスライドKen Fukui
 
【ゲーム理論入門】ChatGPTが作成した ゲーム理論の問題を解く #3 Slide
【ゲーム理論入門】ChatGPTが作成した ゲーム理論の問題を解く #3 Slide【ゲーム理論入門】ChatGPTが作成した ゲーム理論の問題を解く #3 Slide
【ゲーム理論入門】ChatGPTが作成した ゲーム理論の問題を解く #3 Slidessusere0a682
 

Recently uploaded (20)

My Inspire High Award 2024「なぜ議会への関心が低いのか?」
My Inspire High Award 2024「なぜ議会への関心が低いのか?」My Inspire High Award 2024「なぜ議会への関心が低いのか?」
My Inspire High Award 2024「なぜ議会への関心が低いのか?」
 
International Politics I - Lecture 1
International Politics I - Lecture 1International Politics I - Lecture 1
International Politics I - Lecture 1
 
リアル戦国探究in米沢 当日講座1(スタッフ共有用)『兵は詐をもって立つ』についてのスライド
リアル戦国探究in米沢 当日講座1(スタッフ共有用)『兵は詐をもって立つ』についてのスライドリアル戦国探究in米沢 当日講座1(スタッフ共有用)『兵は詐をもって立つ』についてのスライド
リアル戦国探究in米沢 当日講座1(スタッフ共有用)『兵は詐をもって立つ』についてのスライド
 
What I did before opening my business..pdf
What I did before opening my business..pdfWhat I did before opening my business..pdf
What I did before opening my business..pdf
 
リアル戦国探究in米沢 事前講座2スライド(スタッフ共有用)『両雄の強さの秘密』についてのスライド
リアル戦国探究in米沢 事前講座2スライド(スタッフ共有用)『両雄の強さの秘密』についてのスライドリアル戦国探究in米沢 事前講座2スライド(スタッフ共有用)『両雄の強さの秘密』についてのスライド
リアル戦国探究in米沢 事前講座2スライド(スタッフ共有用)『両雄の強さの秘密』についてのスライド
 
TEAMIN Service overview for customer_20240422.pdf
TEAMIN Service overview for customer_20240422.pdfTEAMIN Service overview for customer_20240422.pdf
TEAMIN Service overview for customer_20240422.pdf
 
My Inspire High Award 2024 「本当の『悪者』って何?」
My Inspire High Award 2024 「本当の『悪者』って何?」My Inspire High Award 2024 「本当の『悪者』って何?」
My Inspire High Award 2024 「本当の『悪者』って何?」
 
My Inspire High Award 2024「Yakushima Islandってなんか変じゃない?」.pdf
My Inspire High Award 2024「Yakushima Islandってなんか変じゃない?」.pdfMy Inspire High Award 2024「Yakushima Islandってなんか変じゃない?」.pdf
My Inspire High Award 2024「Yakushima Islandってなんか変じゃない?」.pdf
 
My Inspire High Award2024「外国人が日本のテーブルマナーに驚く理由は?」
My Inspire High Award2024「外国人が日本のテーブルマナーに驚く理由は?」My Inspire High Award2024「外国人が日本のテーブルマナーに驚く理由は?」
My Inspire High Award2024「外国人が日本のテーブルマナーに驚く理由は?」
 
My Inspire High Award 2024「他者と自分、対立を防ぐには?」
My Inspire High Award 2024「他者と自分、対立を防ぐには?」My Inspire High Award 2024「他者と自分、対立を防ぐには?」
My Inspire High Award 2024「他者と自分、対立を防ぐには?」
 
My Inspire High Award 2024  「正義って存在するの?」
My Inspire High Award 2024  「正義って存在するの?」My Inspire High Award 2024  「正義って存在するの?」
My Inspire High Award 2024  「正義って存在するの?」
 
リアル戦国探究in米沢 当日講座2スライド(スタッフ共有用)『人を致すも人に致されず』についてのスライド
リアル戦国探究in米沢 当日講座2スライド(スタッフ共有用)『人を致すも人に致されず』についてのスライドリアル戦国探究in米沢 当日講座2スライド(スタッフ共有用)『人を致すも人に致されず』についてのスライド
リアル戦国探究in米沢 当日講座2スライド(スタッフ共有用)『人を致すも人に致されず』についてのスライド
 
リアル戦国探究in米沢 当日講座3スライド(スタッフ共有用)『糧は三度はさいせず』についてのスライド
リアル戦国探究in米沢 当日講座3スライド(スタッフ共有用)『糧は三度はさいせず』についてのスライドリアル戦国探究in米沢 当日講座3スライド(スタッフ共有用)『糧は三度はさいせず』についてのスライド
リアル戦国探究in米沢 当日講座3スライド(スタッフ共有用)『糧は三度はさいせず』についてのスライド
 
My Inspire High Award 2024 「AIと仲良くなるには?」
My Inspire High Award 2024 「AIと仲良くなるには?」My Inspire High Award 2024 「AIと仲良くなるには?」
My Inspire High Award 2024 「AIと仲良くなるには?」
 
My Inspire High Award 2024      「家族とは何か」
My Inspire High Award 2024      「家族とは何か」My Inspire High Award 2024      「家族とは何か」
My Inspire High Award 2024      「家族とは何か」
 
My Inspire High Award 2024「老いることは不幸なこと?」
My Inspire High Award 2024「老いることは不幸なこと?」My Inspire High Award 2024「老いることは不幸なこと?」
My Inspire High Award 2024「老いることは不幸なこと?」
 
My Inspire High Award 2024「スーパーマーケットで回収されたキャベツ外葉は廃棄されているの?」
My Inspire High Award 2024「スーパーマーケットで回収されたキャベツ外葉は廃棄されているの?」My Inspire High Award 2024「スーパーマーケットで回収されたキャベツ外葉は廃棄されているの?」
My Inspire High Award 2024「スーパーマーケットで回収されたキャベツ外葉は廃棄されているの?」
 
My Inspire High Award 2024「なぜ人は他人と違うところがあってもそれをなかなか誇れないのか?」
My Inspire High Award 2024「なぜ人は他人と違うところがあってもそれをなかなか誇れないのか?」My Inspire High Award 2024「なぜ人は他人と違うところがあってもそれをなかなか誇れないのか?」
My Inspire High Award 2024「なぜ人は他人と違うところがあってもそれをなかなか誇れないのか?」
 
リアル戦国探究in米沢 事前講座1スライド(スタッフ共有用)『川中島の謎』についてのスライド
リアル戦国探究in米沢 事前講座1スライド(スタッフ共有用)『川中島の謎』についてのスライドリアル戦国探究in米沢 事前講座1スライド(スタッフ共有用)『川中島の謎』についてのスライド
リアル戦国探究in米沢 事前講座1スライド(スタッフ共有用)『川中島の謎』についてのスライド
 
【ゲーム理論入門】ChatGPTが作成した ゲーム理論の問題を解く #3 Slide
【ゲーム理論入門】ChatGPTが作成した ゲーム理論の問題を解く #3 Slide【ゲーム理論入門】ChatGPTが作成した ゲーム理論の問題を解く #3 Slide
【ゲーム理論入門】ChatGPTが作成した ゲーム理論の問題を解く #3 Slide
 

Effective java2nd chap04

  • 1. Effective Java Second Edition 社内勉強会資料 第4章 Classes and Interfaces 大槌 剛彦 (@ohtsuchi)
  • 2. 項目13 クラスとメンバーへのアクセス可能性を最小限にする • 情報隠蔽(information hiding) or カプセル化(encapsulation) – – – – 他のモジュールから内部の実装を隠蔽 実装とAPIを分離 APIを通して他のモジュールと通信 利点 • モジュールの並行開発→ 開発スピードのUP • メンテナンスの負担緩和 • アクセス可能性(accessibility)を決定するアクセス制御 (access control) – 宣言された場所 と、 – アクセス修飾子(private, protected, and public) で決まる – 目安 • できるだけアクセスできないように
  • 3. 項目13 クラスとメンバーへのアクセス可能性を最小限にする • トップレベル(ネストしていない)クラス・インタフェース – 2種類のアクセスレベル • package-private • public – 可能ならば package-private にする – public : 互換性を維持するために永久にサポートする義務。APIの一部。 – package-private top-level class を1つのクラスだけが使用している場合 • その使用している1つのクラスの private nested class にする事を検討 • メンバー(field, method, nested class, nested interface) – 4種類のアクセスレベル • • • • – private package-private protected Public できるだけ全てのメンバーをprivateにする
  • 4. 項目13 クラスとメンバーへのアクセス可能性を最小限にする • Serializable を実装している場合 – private と package-private のメンバーであっても公開API の中に leak してしまう(項目74 ) • 古いバージョンでシリアライズ • → 内部表現を変更 • → 新しいバージョンでデシリアライズ • → プログラム失敗 • メソッドをオーバライド – サブクラスでアクセスレベルを低くできない • インタフェースにあるメソッド – 全てpublic • テストを容易にするために – private → package-private まで緩和するのは受け入れられる
  • 5. 項目13 クラスとメンバーへのアクセス可能性を最小限にする • インスタンスフィールド:public にすべきではない → 項目14 – 以下の事を放棄することになる • そのフィールドに保存できる値を制限 • そのフィールドに関係する不変式(invariant)を強制 • そのフィールドが変更された時に何らかの補助処理を行う – 例外 • public static final の定数 は公開してよい(定数) – 基本データ型 – 不変オブジェクト(項目15)への参照 – finalの可変オブジェクトの参照は? » 参照は変更できないが、参照されているオブジェクトは操作できる » 悲惨な結果になる変更が可能 » (例)長さが0ではない配列 → 可変 // Potential security hole! public static final Thing[] VALUES = { ... };
  • 6. 項目13 クラスとメンバーへのアクセス可能性を最小限にする • public static final の配列の修正:2通りの解決 – publicの不変リスト private static final Thing[] PRIVATE_VALUES = { ... }; public static final List<Thing> VALUES = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES)); – 配列のコピーを返すpublicのメソッド private static final Thing[] PRIVATE_VALUES = { ... }; public static final Thing[] values() { return PRIVATE_VALUES.clone(); }
  • 7. 項目14 public のクラスでは、 publicのフィールドではなく、アクセッサーメソッドを使う • public の accessor method (getter) と • 可変クラスに対するmutator (setter) class Point { private double x; private double y; public Point(double x, double y) { this.x = x; this.y = y; } public double getX() { return x; } public double getY() { return y; } public void setX(double x) { this.x = x; } public void setY(double y) { this.y = y; } } – accessor method の提供 • クラス内部の表現形式を変更する柔軟性を保つ
  • 8. 項目15 可変性を最小限にする • 不変クラスにするための5つの規則 – 1. 状態を変更するメソッド(= mutator) を提供しない – 2. クラスが拡張できない事を保証する • → サブクラスに状態を変更されないように – 3. 全てのフィールドをfinalにする – 4. 全てのフィールドをprivateにする – 5. 可変コンポーネントに対する exclusive access を保証する • 可変オブジェクトを参照しているフィールドを持っている場合: – クライアントがそのオブジェクトへの参照を取得できないように – クライアントが提供したオブジェクト参照で初期化してはいけない – accessor からオブジェクトの参照を返してはいけない – defensive copy をする » コンストラクタ » Accessor » readObject (項目76)
  • 9. 項目15 可変性を最小限にする // 複素数を表すクラス public finalclass Complex { private final double re; private final double im; public Complex(double re, double im) { this.re = re; this.im = im; } // 実数部分・虚数部分へのアクセサーを提供 // アクセサー のみ (対応する mutator を持たない) public double realPart() { return re; } public double imaginaryPart() { return im; } // 4つの算術操作:足し算・引き算・掛け算・割り算を提供 public Complex add(Complex c) { return new Complex(re + c.re, im + c.im); } (…以下省略) • 新たなインスタンスを生成して返している (算術操作メソッドの部分) – 関数的方法 • オペランドを変更することなく、関数を適用した結果を返す
  • 10. 項目15 可変性を最小限にする • 不変オブジェクト – スレッドセーフ。同期を必要としない。 – 制限なく共有できる • コピー(#cloneやコピーコンストラクタ)を行う必要が無い – コピー元と同値なので – 既存のクラスを再利用 • 頻繁に使用される値 → 定数を提供 public static final Complex ZERO = new Complex(0, 0); public static final Complex ONE = new Complex(1, 0); public static final Complex I = new Complex(0, 1); – 頻繁に要求されるインスタンスをキャッシュするstatic ファクトリメソッドを提供できる(項目1) – 内部も共有できる • 【例】 BigInteger の negate メソッド – 同じ大きさで反対の符号のBigIntegerを返す – 大きさ=int[] をコピーする必要がない public class BigInteger extends Number … { final int signum; // -1 for negative, 0 for zero, or 1 for positive final int[] mag; … public BigInteger negate() { return new BigInteger(this.mag, -this.signum);
  • 11. 項目15 可変性を最小限にする • 不変オブジェクトの欠点 – 異なる値に対して、別々のオブジェクトが必要 – オブジェクトが大きい場合 • コストが高くつく – (例) BigInteger で 100万ビットのデータの最下位ビットを反転 » 元のインスタンスと1ビットしか違わないのに » → 100万ビットの新たなBigIntegerインスタンスを生成→ 生成コスト高 – Bitset(可変)の場合 » 最下位ビットの1ビットの状態を変更 → 一定時間で可能 – 複数ステップの処理 • 各ステップで新たなオブジェクトを生成 → 最終結果以外の全てのオブジェクトを破棄 → パフォーマンスの問題 • 対処法2つ – 複数ステップを1つの操作で提供する – public の可変 companion class を提供する » (主な例)StringとStringBuilder » (ある状況では)BigInteger と Bitsetもその関係
  • 12. 項目15 可変性を最小限にする • 不変オブジェクトの設計 – 不変性を保証するために、サブクラス化の禁止 • 方法1: class を final にする • 方法2: コンストラクタを全て private or package-private にして、public static factory(項目 1)を追加 // コンストラクタの代わりに、 static factoryを持つ不変クラス public class Complex { private final double re; private final double im; private Complex(double re, double im) { this.re = re; this.im = im; } public static Complex valueOf(double re, double im){ return new Complex(re, im); } ... } • static factoryの利点: – Flexible » 後からキャッシュ機能を追加したり – 名前が明確 (例: #valueOf と #valueOfPolar) » コンストラクタだけの場合、別の生成手段で、同じシグニチャになってしまう事がある
  • 13. 項目15 可変性を最小限にする • 不変オブジェクト:まとめ – できるだけクラスは不変にする • 特に小さなオブジェクトは常に不変にすべき • 大きなオブジェクトも不変にすることを検討 – パフォーマンスを得るために必要な時だけ、 public の可変 companion class を提供 – クラスを不変にできない場合 • その可変性をできるだけ制限 – 理由がない限り、全てのフィールドをfinalにする • コストが高い計算結果(例: hashCode計算)をキャッシュするために 、 finalでない冗長なフィールドを持つ場合あり。 – → String でも使用されている
  • 14. 項目16 継承よりコンポジションを選ぶ • 継承はカプセル化を破る – Superclassの実装詳細に依存 • 後から superclass の実装が変更されたら、subclassが機能しなくなる可能性 // 継承の不適切な利用 public class InstrumentedHashSet<E> extends HashSet<E> { // 要素の挿入回数 private int addCount = 0; … @Override public boolean add(E e) { addCount++; return super.add(e); } @Override public boolean addAll(Collection<? extends E> c) { addCount += c.size(); return super.addAll(c); } public int getAddCount() { return addCount; } } InstrumentedHashSet<String> s = new InstrumentedHashSet<String>(); s.addAll(Arrays.asList("Snap", "Crackle", "Pop"));
  • 15. 項目16 継承よりコンポジションを選ぶ • ニ重にカウントされる – getAddCount → 3ではなく6が返ってくる – HashSet#addAll (AbstractCollection#addAll)は内部で #add を使用しているため – 修理する事もできるが、、、、 • #addAll の Override を止める or – HashSet#addAll が #addを使用して実装されている事実に依存 » → 自己利用 “self-use” • Javaプラットフォームの全ての実装で行われている保証はない • リリースごとに変更される可能性 • #addAll の中で 要素をiterateして #add 呼び出し – HashSet#addAll を呼び出さない » → superclass のメソッドを再実装するのに等しい
  • 16. 項目16 継承よりコンポジションを選ぶ • Composition – 既存クラスを extend する代わりに、 既存クラスを private field にする。 – 新クラスのインスタンスメソッド • 既存クラスの対応するメソッドを呼ぶ • forwarding method と呼ばれる // Wrapper class - 継承の代わりに composition を使用 public class InstrumentedSet<E> extends ForwardingSet<E> { private int addCount = 0; public InstrumentedSet(Set<E> s) { super(s); } … } // 再利用可能な forwarding class public class ForwardingSet<E> implements Set<E> { private final Set<E> s; public ForwardingSet(Set<E> s) { this.s = s; } … public boolean add(E e) { return s.add(e); } … public boolean addAll(Collection<? extends E> c) { return s.addAll(c); } … }
  • 17. 項目16 継承よりコンポジションを選ぶ • InstrumentedSet は 他のSetインスタンスをラップする – wrapper class とも呼ばれる – Decorator pattern Set<Date> s = new InstrumentedSet<Date>(new TreeSet<Date>(cmp)); Set<E> s2 = new InstrumentedSet<E>(new HashSet<E>(capacity)); – 既に使用されているSetインスタンスを一時的に計測 static void walk(Set<Dog> dogs) { InstrumentedSet<Dog> iDogs = new InstrumentedSet<Dog>(dogs); // このメソッド内では、dogsの代わりに、iDogsを使用 } • 委譲(delegation) != (composition と forwarding の組み合わせ) – wrapper object が自分自身を wrapped object へ渡さない限り、委譲ではない
  • 18. 項目16 継承よりコンポジションを選ぶ • 継承が適切の場合 – 本当のサブタイプ関係がある場合だけ – クラスBは、クラスAとの間に「is-a」関係が存在している場合のみ、クラスA を拡張 • 「全てのBは本当にAであるか」 – javaのライブラリで原則を破っている例 • Stack (extends Vector) • Properties (extends Hashtable) • → どちらの場合も composition にするほうが適切だった
  • 19. 項目17 継承のために設計および文章化する、 でなければ継承を禁止する • [オーバライド可能なメソッド]を呼び出すメソッド – 呼び出しに関する記述は「This implementation」で始まる public abstract class AbstractCollection<E> implements Collection<E> { … public abstract Iterator<E> iterator(); … /** * {@inheritDoc} * * <p>This implementation iterates over the collection looking for the * specified element. If it finds the element, it removes the element * from the collection using the iterator's remove method. * *… */ public boolean remove(Object o) { Iterator<E> it = iterator(); if (o==null) { … – #iterator をオーバライドすることによって、#remove に影響を与える事が 記述されている
  • 20. 項目17 継承のために設計および文章化する、 でなければ継承を禁止する • 継承のために設計されたクラス – →サブクラスを書いてテスト • 継承を可能にするための制約 – コンストラクタは、オーバライド可能なメソッドを呼び出してはいけない public class Super { // コンストラクタがオーバライド可能なメソッドを呼び出し public Super() { overrideMe(); } public void overrideMe() {} } public final class Sub extends Super { private final Date date; // Blank final, set by constructor Sub() { date = new Date();} // コンストラクタ @Override public void overrideMe() { System.out.println(date); } public static void main(String[] args) { Sub sub = new Sub(); sub.overrideMe(); } }
  • 21. 項目17 継承のために設計および文章化する、 でなければ継承を禁止する • 実行結果例 null Tue Feb 04 11:01:18 JST 2014 • Cloneable または Serializable する場合にもコンストラクタと似た振る舞い – #clone – #readObject – 上記メソッドからオーバライド可能なメソッドを呼び出してはいけない • 文書化されていないクラスのサブクラス化の禁止 – 方法1:クラスをfinal にする – 方法2:コンストラクタを全て private or package-private にして 、public static factory を提供
  • 22. 項目18 abstract class よりも interface を選ぶ • abstract class – メソッドの実装を含む • Interface – メソッドの実装を含まない • (※)java8 では default 実装を定義できるそうですが… • javaは単一継承のみ – クラスは2つ以上の親は持てない – 2つのクラスに同じ抽象クラスを拡張させたければ → 高い位置(両方のクラスの先祖) に定義する必要あり
  • 23. 項目18 abstract class よりも interface を選ぶ • Interface – mixin を定義するのに理想的 – 階層を持たない型 public interface Singer { AudioClip sing(Song s); } public interface Songwriter { Song compose(boolean hit); } public interface SingerSongwriter extends Singer, Songwriter { AudioClip strum(); void actSensitive(); }
  • 24. 項目18 abstract class よりも interface を選ぶ • 骨格実装 (skeletal implementation) – interface ごとに – 実装補助を提供 – 慣例として、AbstractInterface と呼ばれる • Collections Framework で提供している骨格実装の例 – AbstractCollection, AbstractSet, AbstractList, AbstractMap • 骨格実装の書き方 – interface を調べる – 基本操作を決める • → abstract method にする – 他の全てのメソッド • →具体的な実装を提供
  • 25. 項目18 abstract class よりも interface を選ぶ • 骨格実装の例 – int[] を List<Integer> として見せる Adapter – static factory の中に隠蔽されている anonymous class static List<Integer> intArrayAsList(final int[] a) { if (a == null) throw new NullPointerException(); return new AbstractList<Integer>() { public Integer get(int i) { return a[i]; // Autoboxing (Item 5) } @Override public Integer set(int i, Integer val) { int oldVal = a[i]; a[i] = val; // Auto-unboxing return oldVal; // Autoboxing } public int size() { return a.length; } }; } • ※パフォーマンスはそれほど良いわけではない (boxing 、unboxing をしているため)
  • 26. 項目18 abstract class よりも interface を選ぶ • Map.Entryの骨格実装例 public abstract class AbstractMapEntry<K,V> implements Map.Entry<K,V> { // Primitive operations public abstract K getKey(); public abstract V getValue(); // 変更可能な Mapの Entries は、このメソッドを override しなければならない public V setValue(V value) { throw new UnsupportedOperationException(); } // Implements the general contract of Map.Entry.equals @Override public boolean equals(Object o) { if (o == this) return true; if (! (o instanceof Map.Entry)) return false; Map.Entry<?,?> arg = (Map.Entry) o; return equals(getKey(), arg.getKey()) && equals(getValue(), arg.getValue()); } … }
  • 27. 項目19 型を定義するためだけに interface を使用する • interface は 型を定義するためだけに使用すべき • 定数を提供するために使用すべきではない – ダメな例: • 定数インタフェース (constant interface) • 選択肢 – 既存の class または interface に強く結びついている場合: • その class または interface に定数を追加 – (例)数字(Integer や Floatなど)クラス の MIN_VALUE や MAX_VALUE – 定数が列挙型のメンバーとして見なされるのがbestならば: • enum type で定数を提供 (項目30) – そうでなければ… • インスタンス化不能な utility class で定数を提供
  • 28. 項目20 タグ付クラスよりクラス階層を選ぶ // Tagged class - クラス階層より、かなり劣る class Figure { enum Shape { RECTANGLE, CIRCLE }; // Tag field - the shape of this figure final Shape shape; // These fields are used only if shape is RECTANGLE double length; double width; // This field is used only if shape is CIRCLE double radius; // Constructor for circle Figure(double radius) { shape = Shape.CIRCLE; this.radius = radius; } // Constructor for rectangle Figure(double length, double width) { shape = Shape.RECTANGLE; this.length = length; this.width = width; }
  • 29. 項目20 タグ付クラスよりクラス階層を選ぶ double area() { switch(shape) { case RECTANGLE: return length * width; case CIRCLE: return Math.PI * (radius * radius); default: throw new AssertionError(); } } } • 欠点 – 決まりきったコードで散らかっている • enum 宣言 • tag field • switch 文 – メモリ量が増加 • 他の特性に属するフィールドを抱えているため – 特性の追加時にソースの修正が必要 • switch 文 に case を追加しなければならない
  • 30. 項目20 タグ付クラスよりクラス階層を選ぶ • サブタイプ化 // クラス階層による置き換え abstract class Figure { abstract double area(); } class Circle extends Figure { final double radius; Circle(double radius) { this.radius = radius; } double area() { return Math.PI * (radius * radius); } } class Rectangle extends Figure { final double length; final double width; Rectangle(double length, double width) { this.length = length; this.width = width; } double area() { return length * width; } } • 各特性の実装に対して → 独自のクラスを定義 – 自分と無関係なデータフィールドを負っていない • 全ての field が final
  • 31. 項目21 戦略を表現するために関数オブジェクトを使用する • java は 関数ポインタを提供していないが、オブジェクトへの参照を使用できる – [他のオブジェクト]に対して操作を行うメソッドを持つオブジェクトを定義 • • • • 他のオブジェクトがそのメソッドに明示的に渡される そのようなメソッドを1つだけ公開 関数オブジェクト(function object)と呼ばれる 戦略(Strategy)パターンを実装 – 戦略を表すインタフェース(Strategy interface) public interface Comparator<T> { public int compare(T t1, T t2); } – 個々の具象戦略クラス(Concrete strategy class) class StringLengthComparator implements Comparator<String> { public int compare(String s1, String s2) { return s1.length() - s2.length(); } } » StringLengthComparatorの戦略: • 辞書順ではなく、文字列の長さで順序付け
  • 32. 項目21 戦略を表現するために関数オブジェクトを使用する • Stateless – シングルトンにするのに適している class StringLengthComparator { private StringLengthComparator() { } public static final StringLengthComparator INSTANCE = new StringLengthComparator(); public int compare(String s1, String s2) { return s1.length() - s2.length(); } } • anonymous classで使用 Arrays.sort(stringArray, new Comparator<String>() { public int compare(String s1, String s2) { return s1.length() - s2.length(); } }); – → 呼び出し毎に新たなインスタンス生成 • 繰り返し実行する場合は private static final にして再利用を検討
  • 33. 項目21 戦略を表現するために関数オブジェクトを使用する • concrete strategy class は public にする必要はない – “host class” の private nested class にできる class Host { private static class StrLenCmp implements Comparator<String>, Serializable { public int compare(String s1, String s2) { return s1.length() - s2.length(); } } public static final Comparator<String> STRING_LENGTH_COMPARATOR = new StrLenCmp(); … } – Stringクラス の CASE_INSENSITIVE_ORDER はこのパターン public final class String implements java.io.Serializable, Comparable<String>, CharSequence { … public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator(); private static class CaseInsensitiveComparator implements Comparator<String>, java.io.Serializable { public int compare(String s1, String s2) { …
  • 34. 項目22 非staticのメンバークラスより staticのメンバークラスを選ぶ • nested class – 他のclass内に定義されたclass – enclosing class に対して仕えるためだけに存在すべき – 4種類 • static member class • nonstatic member class • anonymous class • local class • enclosing instance への参照が必要ならば nonstatic にする • →そうでなければ、staticにする。 • クラスがメソッド内に属していて、1箇所からのみインスタンスを生成する必要があり、 そのクラスを特徴づける型が存在すれば、anonymous class にする