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 if
s kodunun orada olması gerekmez. Doğal olarak, int
s veya float
s 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 ( if
s) 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
)
data
sıkıştırılmış (arayın compress(data)
ve geri gönderin)
data
şifreli (arayın encrypt(data)
ve iade edin)
data
sı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, class
anahtar kelimeyle değiştirilecek interface
(örneğin, C #, Java ve / veya PHP gibi dillerle ilgileniyorsanız) veya class
anahtar kelime kalacak gibi arayüzlerle değiştirilme olasılığı çok yüksektir . C ++ 'da kodlamanız gerekir Compress
ve Encrypt
yö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. Process
Yö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, if
artı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 Compression
ve Encryption
sı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 if
ve en azından ortadan kaldırabilen Ixrec'in çözümünü kapabilirsiniz .else
if
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.
if
ifadeler olma ihtimali var mı?