必要に応じた保護コピー

7170 ワード

クラスのクライアントは、このクラスの制約条件を破壊するために最善を尽くすと仮定します.そのため、保護された設計プログラムが必要です.demo:
 
 1 import java.util.Date;
 2 
 3 public final class Period {
 4     private final Date start;
 5     private final Date end;
 6     public Period(Date start,Date end) {
 7         if(start.compareTo(end) > 0){
 8             throw new IllegalArgumentException(start + " after " + end);
 9         }
10         this.start = start;
11         this.end = end;
12     }
13     
14     public Date start(){
15         return start;
16     }
17     
18     public Date end(){
19         return end;
20     }
21     //remainder omitted
22 }

 
このクラスには問題がないように見えますが、時間は変えられません.しかし、Dateクラス自体は可変です.
1         Date start = new Date();
2         Date end = new Date();
3         Period period = new Period(start, end);
4         end.setYear(78);
5         System.out.println(period.end());

 
 
Periodインスタンスの内部情報を修正から保護するためには、コンストラクタの可変パラメータごとに保護コピー(defensive copy)が必要です.
 
1     public Period(Date start,Date end) {
2         this.start = new Date(start.getTime());
3         this.end = new Date(end.getTime());
4         if(this.start.compareTo(this.end) > 0){
5             throw new IllegalArgumentException(this.start + " after " + this.end);
6         }
7     }        

 
保護コピーは、パラメータの有効性をチェックする前に行われ、元のオブジェクトではなくコピー後のオブジェクトに対して有効性チェックが行われます.
パラメータタイプが信頼できない方子でクラス化できるパラメータについては、cloneメソッドを使用して保護コピーを行わないでください.Periodを変更することで
 
1         Date start = new Date();
2         Date end = new Date();
3         Period period = new Period(start, end);
4         period.end().setYear(98);
5         System.out.println(period.end());

 
 
二次攻撃を防ぐためにend()をコピーオブジェクトに戻すことができます.
1     public Date end(){
2         return new Date(end.getTime());
3     }

 
しかし、このように書くのはイライラするので、必要性を把握する必要があります.
パラメータの保護コピーは、可変クラスだけではありません.作成方法とコンストラクタを作成するたびに、お客様が提供するオブジェクトを内部データ構造に入れることを許可する場合は、お客様が提供するオブジェクトが可変である可能性があるかどうか、私がこの可変性を許容できるかどうかを考慮する必要があります.特にlist、mapなどの接続要素を使用する場合.内部コンポーネントがクライアントに返される場合も、内部参照を指すデータを返すことができるかどうかを考慮します.あるいは、コピーを使用しないで、可変オブジェクトを返すこともできます.例:Colletions.unmodifiableList(Listlist)クラスがクライアントから取得またはクライアントに戻る可変コンポーネントを持っている場合、クラスはこれらのコンポーネントを保護的にコピーする必要があります.コピーのコストが制限され、クラスがクライアントを信頼して変更しないか、適切な変更がない場合は、クライアント呼び出し者の責任(変更しないか、効果的に変更する方法)をドキュメントに示す必要があります.特に、可変コンポーネントのライフサイクルが長い場合や、多層的に伝達される場合、隠された問題が漏れるのは恐ろしいことが多い.
 
保護コピーを行う設計の原則は、クライアントがクラスを使用すると、あなたの設計クラスの原則を破壊し、プログラムに必要な効果を達成できません.
 
転載:http://blog.csdn.net/partner4java/article/details/7592950