Kod tasarımı yaparken, iki seçeneğiniz var.
- sadece halledin, bu durumda hemen hemen her çözüm sizin için işe yarayacak
- Pedantik olmak ve dilin tuhaflıklarından ve ideolojisinden faydalanan bir çözüm tasarlamak (bu durumda OO dilleri - polimorfizmin karar vermek için bir araç olarak kullanılması)
Ben ikisinin ilkine odaklanmayacağım, çünkü söylenecek hiçbir şey yok. Çalışmasını sağlamak istiyorsanız, kodu olduğu gibi bırakabilirsiniz.
Peki, onu sinsi bir şekilde yapmayı seçtiyseniz ve gerçekte istediğiniz gibi tasarım desenleriyle sorunu çözdüyseniz ne olurdu?
Aşağıdaki sürece bakıyor olabilirsiniz:
OO kodunu tasarlarken, koddaki çoğu ifs kodunun orada olması gerekmez. Doğal olarak, ints veya floats gibi iki skaler tipini karşılaştırmak istiyorsanız, sahip olma ihtimaliniz yüksektir if, ancak konfigürasyona dayalı prosedürleri değiştirmek istiyorsanız, istediğiniz şeyi elde etmek için polimorfizmi kullanabilirsiniz , kararları hareket ettirin ( ifs) iş mantığınızdan nesnelerin somutlaştırıldığı bir yere - fabrikalara .
Şu andan itibaren, işleminiz 4 ayrı yoldan geçebilir:
dataşifreli veya sıkıştırılmamış (hiçbir şey arama, geri dönme data)
datasıkıştırılmış (arayın compress(data)ve geri gönderin)
dataşifreli (arayın encrypt(data)ve iade edin)
datasıkıştırılmış ve şifrelenmiş (arayın encrypt(compress(data))ve iade edin)
Sadece 4 patikaya bakarak bir sorun bulursun.
3'ü çağıran bir işleminiz var (teorik olarak 4, eğer hiç birşeyi çağırmazsanız) verileri işleyen ve sonra döndüren farklı yöntemler. Yöntemlerin ortak adları (yöntemlerin davranışlarını iletme şekilleri) ortak API adı verilen farklı adları vardır .
Bağdaştırıcı şablonunu kullanarak, ortaya çıkan ad çarpışmasını çözebiliriz (ortak API'yi birleştirebiliriz). Basitçe söylemek gerekirse, adaptör iki uyumsuz ara yüzün birlikte çalışmasına yardımcı olur. Ayrıca, bağdaştırıcı, API uygulamalarını birleştirmeye çalışan sınıfların oluşturduğu yeni bir bağdaştırıcı arabirimi tanımlayarak çalışır.
Bu somut bir dil değil. Bu genel bir yaklaşımdır, herhangi bir anahtar kelime herhangi bir türde olabilir, C # gibi bir dilde generics ( <T>) ile değiştirebilirsiniz .
Varsayıyorum, şu anda sıkıştırma ve şifrelemeden sorumlu iki sınıfınız olabilir.
class Compression
{
Compress(data : any) : any { ... }
}
class Encryption
{
Encrypt(data : any) : any { ... }
}
Bir işletme dünyasında, bu belirli sınıfların bile, classanahtar kelimeyle değiştirilecek interface(örneğin, C #, Java ve / veya PHP gibi dillerle ilgileniyorsanız) veya classanahtar kelime kalacak gibi arayüzlerle değiştirilme olasılığı çok yüksektir . C ++ 'da kodlamanız gerekir Compressve Encryptyöntemler saf bir sanal olarak tanımlanır .
Bir adaptör yapmak için ortak bir arayüz tanımlarız.
interface DataProcessing
{
Process(data : any) : any;
}
O zaman onu kullanışlı kılmak için arayüzün uygulamalarını sağlamalıyız.
// 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)
);
}
}
Bunu yaparak, her biri tamamen farklı bir şey yapan ancak her biri aynı ortak API'yi sağlayan 4 sınıfla karşılaşırsınız. ProcessYöntemi.
Hiçbiri / şifreleme / sıkıştırma / her iki kararla ilgilendiğiniz iş mantığınızda, nesneyi daha DataProcessingönce tasarladığımız arayüze bağlı olacak şekilde tasarlayacaksınız .
class DataService
{
private dataProcessing : DataProcessing;
public DataService(dataProcessing : DataProcessing)
{
this.dataProcessing = dataProcessing;
}
}
Sürecin kendisi bu kadar basit olabilir:
public ComplicatedProcess(data : any) : any
{
data = this.dataProcessing.Process(data);
// ... perhaps work with the data
return data;
}
Başka şart yok. Sınıf DataService, dataProcessingüyeye iletildiğinde verilerle gerçekten ne yapılacağına dair hiçbir fikri yoktur ve bu onunla gerçekten ilgilenmez, bu onun sorumluluğu değildir.
İdeal olarak, çalıştıklarından emin olmak için oluşturduğunuz 4 adaptör sınıfını test eden ünite testlerine sahip olursunuz, test geçişinizi yaparsınız. Ve geçerlerse, kodunuzda nerede çağırırlarsanız çalınacaklarından emin olabilirsiniz.
Yani bu şekilde yapmak, ifartık benim kodumda olmayacak?
Hayır. İş mantığınızda şartlı olma olasılığınız daha düşüktür, ancak yine de bir yerlerde olmaları gerekir. Burası senin fabrikaların.
Ve bu iyi. Yaratma ile ilgili endişeleri birbirinden ayırıyorsunuz ve kodu gerçekten kullanıyorsunuz. Fabrikalarınızı güvenilir hale getirirseniz (Java’da Google’dan Guice framework gibi bir şey kullanmaya bile gidebilirsiniz ), işletme mantığınızda enjekte edilecek doğru sınıfı seçmekten endişe duymazsınız. Çünkü fabrikalarınızın çalıştığını ve sorulanı teslim edeceğini biliyorsunuz.
Bütün bu sınıflara, arayüzlere vb. Sahip olmak gerekli midir?
Bu bizi tekrar başlangıç noktasına getiriyor.
OOP'de, polimorfizmi kullanma yolunu seçerseniz, gerçekten tasarım kalıplarını kullanmak istiyorsanız, dilin özelliklerinden yararlanmak ve / veya her şeyi takip etmek istiyorsanız, bir nesne ideolojisi, öyleyse öyledir. Ve o zaman bile, bu örnek bile ihtiyacı olacak tüm fabrikalar göstermez ve eğer refactor Compressionve Encryptionsınıfları ve siz de onların uygulamalarını içerecek şekilde var onları yerine arabirimleri olun.
Sonunda, çok özel şeylere odaklanan yüzlerce küçük sınıf ve arayüzle karşılaşıyorsunuz. Bu mutlaka kötü bir şey değildir, ancak tek isteğiniz iki sayı eklemek kadar basit bir şey yapmaksa, sizin için en iyi çözüm olmayabilir.
Bunu hemen ve çabucak halletmek istiyorsanız, bence en azından bir düzlükten bile daha kötü olan blokları else ifve en azından ortadan kaldırabilen Ixrec'in çözümünü kapabilirsiniz .elseif
Bu benim için iyi OO tasarımı yapmanın bir yoludur. Uygulamalardan ziyade arayüzlere kodlama yapmak, bunu son birkaç yıldır böyle yaptım ve en rahat olduğum yaklaşım bu.
Şahsen if-if programlamayı daha çok seviyorum ve 5 kod satırı üzerindeki daha uzun çözümü çok takdir ediyorum. Kod tasarlamaya alışkınım ve onu okumak çok rahat.
Güncelleme 2: Çözümümün ilk sürümü hakkında çılgınca bir tartışma oldu. Tartışma, çoğunlukla özür dilediğim benden kaynaklanıyor.
Cevabı, çözüme bakmanın yollarından biri olacak şekilde düzenlemeye karar verdim, sadece bir değil. Aynı zamanda dekoratör kısmını da çıkarttım, bunun yerine cepheyi kastetmiştim, sonunda tamamen bırakmaya karar verdim, çünkü bir adaptör bir cephe değişimidir.
ififadeler olma ihtimali var mı?