設計の宣言的スタイル (273) †
要約 †
- 273-1(Once your design 〜)
- INTENTION-REVEALING INTERFACE、SIDE-EFFECT-FREE FUNCTION、ASSERTIONをひとたび設計に取り入れれば、設計はより宣言的になるでしょう。宣言的設計の多くの利点は合成可能な要素を使うことで得られます。
- 273-2(A supple design 〜)
- 柔軟な設計により、クライアントコードの設計が宣言的スタイルを利用しやすくなります。それを示すために、次のセクションでは、この章でとりあげたパターンをまとめ、SPECIFICATIONをより柔軟で宣言的にします。
宣言的スタイルでSPECIFICATIONSを拡張する †
- 273-3(Chapter 9 covered 〜)
- 274-1(SPECIFICATION is an adaption 〜)
- SPECIFICATIONは述語です。述語には、選択的に利用できる便利な性質があります。これは複雑なルールを伴う状況下で役立ちます。
論理演算子を使ってSPECIFICATIONSを合成する
- 274-2(When using SPECIFICATION 〜)
- SPECIFICATIONSを使うとき、合成して使いたい状況がよくあります。SPECIFICATIONSは述語の一例なので、AND、OR、NOTの演算子を使って合成したり修正したりできます。これらの論理演算子は述語に閉じています。つまり、SPECIFICATIONSの合成はCLOSURE OF OPERATIONSです。
- 274-3(As significant 〜)
- 重要な一般化された性質がSPECIFICATIONには組み込まれています。そのため、全種類のSPECIFICATIONとして利用できる抽象クラスやインタフェースを作るのに便利です。これは、引数の型がより抽象度の高い型になることを意味します。
public interface Specification {
boolean isSatisfiedBy(Object candidate);
}
- 274-4(This abstraction call for 〜)
- この抽象化により、メソッドの最初にガード節が必要になりますが、機能には影響を与えません。例えば、Container Specification(236ページ9章の例より)は次のように修正されます。
public class ContainerSpecification implements Sepcification {
...
public boolean isSatisfiedBy(Object candidate) {
if (!(candidate instanceof Container)) return false;
return ((Container)candidate).getFeatures().contains(requiredFeature);
}
}
- 274-5(Now, let's extend 〜)
- さらに、3つのオペレーションを加えてSpecificationインタフェースを拡張しましょう。
Specification and(Specification other);
Specification or(Specification other);
Specification not();
- 275-1(Recall that 〜)
- 通風コンテナや強化コンテナを必要とするように設定されたContainer Specificationsがあったことを思い出してください。揮発性で爆発しやすい科学物質はおそらくそれら両方のSPECFICATIONを必要とするでしょう。新しく追加されたメソッドを使えば簡単に実現できます。
Specification ventilated = new ContainerSpecification(VENTILATED);
Specification armored = new ContainerSpecification(ARMORED)
Specification both = ventilated.and(armored)
- 275-3(Suppose we had 〜)
- 通風の別種類のContainerがあると仮定してください。どちらに詰められてもかまわない化学物質があるとします。それらの化学物質がどちらかのタイプのコンテナに置かれるということです。
Specification ventilatedType1 = new ContainerSpecification(VENTILATED_TYPE_1);
Specification ventilatedType2 = new ContainerSpecification(VENTILATED_TYPE_2);
Specification either = ventilatedType1.or(ventilatedType2)
- 275-4(If it was wasteful 〜)
- 砂を特別なコンテナに詰めるのが無駄と考える場合、特別な機能を持たない安いコンテナを指定することでそれを禁止できます。
Specification cheap = (ventilated.not()).and(armored.not());
- 275-6(The ability 〜)
- 単純な要素から複雑な要素を組み立てる能力はコードの表現を豊かにします。合成は宣言的スタイルで記述されます。
- 276-1(Depending on 〜)
- SPECIFICATIONSがどう実装されるかにより、演算子は提供し易くも提供し難くもなります。以下の示すのは、とても簡単な実装です。これは、説明のための例です。他のパターン同様、実装方法はたくさんあります。
public abstract class AbstractSpecification implements Specifiation { ... }
public class AndSpecification extends AbstractSpecification { ... }
public class OrSpecification extends AbstractSpecification { ... }
public class NotSpecification extends AbstractSpecification { ... }
- 277-1(The code wasa 〜)
- このコードは読みやすいように記述されています。これらの実装が非効率な状況はありますが、その場合は他の実装を選択できます。重要なのは、ドメインの重要な概念を捉えたモデルとそのモデルに忠実な実装です。これらがパフォーマンスの問題を解決するための多くの余地を残します。
- 278-1(Also, this 〜)
- 完全な一般性は多くの場合不要です。特に、ANDが他の演算子より多く使用される傾向にあります。必要なものがANDだけであれば、ANDだけを実装してください。
- 278-2(Way back in Chapter 2 〜)
- 2章の30ページにおける対話の例に戻りますが、開発者は明らかにSPECIFICATIONに"sagisfied by"の振る舞いを実装していません。その時点では、オーダーメイドのために使われたに過ぎません。しかしそうであっても抽象化は損なわれず機能の追加は比較的簡単なままです。パターンを使用することは不必要な機能を作成することではありません。概念がはっきりすれば、機能は後から追加できるのです。
例:COMPOSITE SPECIFICATIONの別の実装
- 278-3(Some implementation 〜)
- 細粒度のオブジェクトに適さない実装をもつ環境があります。その場合には、別の実装を検討すべきです。
- 278-4(Here is an example 〜)
- ここでは、複合化されたSPECIFICATIONを文字列や配列としてエンコードする実装の例を示します。(次のようなStack)
- AndSpecificationOperator?
- NotSpecificationOperator?
- Armored
- NotSpecificationOperator?
- Ventilated
- 279-1(When you want to test 〜)
- 仕様をみたしているかどうか候補に対しテストをするとき、この構造を解析する必要があります。この解析は、それぞれの要素をスタックから取り出し、それから、それを評価するもしくは演算子にしたがって次の要素を取り出します。
- 279-2(The design has 〜)
- この設計の良い点と悪い点は以下のとおりです。
- 良い点
- 悪い点
- 279-3(You have to 〜)
- トレードオフを考慮して環境に適した実装を見つける必要があります。同じパターンとモデルの上に異なる実装を構築できます。
包摂
- 279-4(This final feature 〜) から 280-2(But what they asked for 〜)
- 新しいSPECIFICATIONで、古いSPECIFICATIONが満たされなくなってしまう問題が生じる例。
- 280-4(A more stringent 〜)
- より厳しいSPECは厳しくないSPECを包摂します。これは、以前の要求がなおざりにされることなく行われます。
- 280-5(In the language of 〜)
- SPECIFICATIONの言語の中では、新しいSPECIFICATIONが古いSPECIFICATIONを包摂するといえます。それは、新しいSPECを満たすいずれの候補も古いSPECを満たすからです。
- 281-2(Another practical special case 〜)
- Container Specificationの問題を解決するさらに別の特別なケースは、包摂と1つの論理演算子ANDをもつSPECIFICATIONインタフェースを使うことです。
AND演算子だけをもつ実装を提供するのは単純です。
A AND B -> A
- もしくは、より複雑なケースではこうなります。
A AND B AND C -> A AND B
- 281-3(So if the Composite Specification 〜)
- Container SpecificationがANDで結び付けられたリーフのSPECIFICATIONをすべて集めることができるなら、包摂するSPECIFICATIONが包摂される側のSPECIFICATIONのリーフをすべて持っているかどうかチェックするだけですみます。包摂する側のリーフはされる側のリーフのスーパーセットになるのです。
- 282-1(This interaction 〜)
- この相互作用は、リーフのSPECIFICATIONや他の合成されたSPECIFICATIONと比較するように拡張できます。ORやNOTが含まれると、証明はもっと複雑になります。多くの場合、いくつかの演算子を使わないか包摂を使わなかいかどちらかを選択し複雑さを避けるのが最上です。両方が必要な場合には、難しさを正当化するだけの十分な利点があるか慎重に検討してください。
担当者のつぶやき †
- p.274の2番目のコードがまちがっている。
- p.276の図がコードとあってないような。。。
みんなの突っ込み †
- "Declarative Design"と"Declarative Style of Design"の違いをズバっと一言で要約するとどうなるのでしょうか?分かるようで分からない・・・ -- 和智?