コードを設計する場合、常に2つのオプションがあります。
- ちょうどそれを成し遂げてください、その場合、ほとんどすべてのソリューションがあなたのために働くでしょう
- 独創的であり、その言語とそのイデオロギーの癖を活用するソリューションを設計します(この場合のオブジェクト指向言語-決定を提供する手段としての多型の使用)
言うべきことは何もないので、2つのうちの最初の1つに焦点を合わせるつもりはありません。動作させたいだけなら、コードをそのままにしておくことができます。
しかし、あなたがそれをつまらない方法で行うことを選択し、あなたが望んだ方法で実際にデザインパターンで問題を解決した場合、どうなりますか?
次のプロセスを見ることができます。
OOコードを設計するとき、コード内にあるのほとんどはif
そこにある必要はありません。当然、int
sやfloat
s などの2つのスカラー型を比較したい場合はを持つ可能性がありますがif
、構成に基づいて手順を変更したい場合は、ポリモーフィズムを使用して目的を達成し、決定を移動できます(if
s)ビジネスロジックから、オブジェクトがインスタンス化される場所- 工場へ。
現在、プロセスは4つの別々のパスを通過できます。
data
暗号化も圧縮もされていない(何も呼び出さず、return data
)
data
圧縮されている(呼び出しcompress(data)
て返す)
data
暗号化されている(呼び出しencrypt(data)
て返す)
data
圧縮および暗号化されている(呼び出しencrypt(compress(data))
て返す)
4つのパスを見るだけで、問題が見つかります。
データを操作して返す3つの異なるメソッド(理論的には4を1つと見なさない場合は4)を呼び出す1つのプロセスがあります。メソッドには異なる名前、いわゆるパブリックAPI(メソッドが動作を通信する方法)があります。
アダプターパターンを使用して、発生した名前colision(パブリックAPIを統合できます)を解決できます。簡単に言うと、アダプターは、互換性のない2つのインターフェースが連携するのに役立ちます。また、アダプターは、新しいアダプターインターフェイスを定義することで機能します。クラスは、API実装を統合しようとします。
これは具体的な言語ではありません。これは一般的なアプローチであり、anyキーワードは任意のタイプであることを表すために存在します。C#のような言語では、generics(<T>
)に置き換えることができます。
現時点では、圧縮と暗号化を担当する2つのクラスを持つことができると仮定します。
class Compression
{
Compress(data : any) : any { ... }
}
class Encryption
{
Encrypt(data : any) : any { ... }
}
企業の世界では、これらの特定のクラスでさえ、class
キーワードに置き換えられるinterface
(C#、Java、PHPなどの言語を扱う場合)、またはclass
キーワードが残るなど、インターフェイスに置き換えられる可能性が非常に高くなりますが、C ++でコーディングする場合Compress
、Encrypt
メソッドは純粋仮想として定義されます。
アダプタを作成するには、共通のインターフェイスを定義します。
interface DataProcessing
{
Process(data : any) : any;
}
次に、インターフェースの実装を提供して、便利なものにする必要があります。
// when neither encryption nor compression is enabled
class DoNothingAdapter : DataProcessing
{
public Process(data : any) : any
{
return data;
}
}
// when only compression is enabled
class CompressionAdapter : DataProcessing
{
private compression : Compression;
public Process(data : any) : any
{
return this.compression.Compress(data);
}
}
// when only encryption is enabled
class EncryptionAdapter : DataProcessing
{
private encryption : Encryption;
public Process(data : any) : any
{
return this.encryption.Encrypt(data);
}
}
// when both, compression and encryption are enabled
class CompressionEncryptionAdapter : DataProcessing
{
private compression : Compression;
private encryption : Encryption;
public Process(data : any) : any
{
return this.encryption.Encrypt(
this.compression.Compress(data)
);
}
}
これを行うと、最終的に4つのクラスになり、それぞれがまったく異なることを行いますが、それぞれが同じパブリックAPIを提供します。Process
方法。
none / encryption / compression / bothの決定を扱うビジネスロジックでは、DataProcessing
以前に設計したインターフェイスに依存するようにオブジェクトを設計します。
class DataService
{
private dataProcessing : DataProcessing;
public DataService(dataProcessing : DataProcessing)
{
this.dataProcessing = dataProcessing;
}
}
プロセス自体は次のように簡単になります。
public ComplicatedProcess(data : any) : any
{
data = this.dataProcessing.Process(data);
// ... perhaps work with the data
return data;
}
条件なし。クラスDataService
は、データがdataProcessing
メンバーに渡されたときにデータで実際に何が行われるのか分かりません。また、それは実際には気にせず、その責任ではありません。
理想的には、作成した4つのアダプタークラスをテストする単体テストを実行して、それらが機能することを確認し、テストに合格するようにします。そして、それらが合格すれば、コードのどこで呼び出しても、確実に機能することを確信できます。
このようにif
してやると、コードにsが含まれなくなりますか?
いいえ。ビジネスロジックに条件が含まれる可能性は低くなりますが、それらはどこかにある必要があります。場所はあなたの工場です。
そしてこれは良いことです。作成の懸念と実際にコードを使用することを分離します。工場の信頼性を高めれば(Javaでは、Google のGuiceフレームワークのようなものまで使用できます)、ビジネスロジックでは、注入する適切なクラスを選択することを心配しません。あなたの工場が機能し、求められているものを提供することを知っているからです。
これらすべてのクラス、インターフェースなどが必要ですか?
これにより、最初に戻ります。
OOPで、ポリモーフィズムを使用するパスを選択する場合、実際にデザインパターンを使用する場合、言語の機能を活用する場合、および/またはオブジェクトイデオロギーであるすべてをフォローする場合は、そうです。その場合でも、この例では必要なすべてのファクトリーも示していないためCompression
、Encryption
クラスとクラスをリファクタリングし、代わりにインターフェースを作成する場合は、実装も含める必要があります。
最終的には、非常に具体的なことに焦点を合わせた何百もの小さなクラスとインターフェースになります。これは必ずしも悪いことではありませんが、2つの数字を追加するだけの簡単なことをしたいだけであれば、最善の解決策ではないかもしれません。
あなたがそれをすぐに終わらせたいなら、Ixrecのソリューションをつかむことができます。彼は少なくともブロックelse if
とelse
ブロックを削除することができました。私の意見では、それは平野よりも少し悪いですif
。
これが私の優れたオブジェクト指向設計の方法です。実装ではなくインターフェースにコーディングすることは、過去数年にわたってこれを行ってきた方法であり、私が最も満足しているアプローチです。
私は個人的にif-lessプログラミングが好きであり、5行のコードでより長いソリューションを評価したいと思っています。それは私がコードを設計するのに慣れている方法であり、それを非常に快適に読んでいます。
更新2:私のソリューションの最初のバージョンについては激しい議論がありました。議論の大部分は私が原因で、謝罪します。
私は答えを編集することにしました。それは解決策を見る方法の1つであり、唯一の方法ではないということです。また、代わりにファサードを意味するデコレータ部分も削除しましたが、アダプターはファサードのバリエーションであるため、最終的に完全に除外することにしました。
if
声明がありそうですか?