"Merhaba arkadaş!"
"Merhaba, Bilaabo!"
"Hala biraz zamanımız var, bu yüzden size üç kalıptan daha bahsedeceğim."
"Üç tane daha mı? Toplam kaç tane var?"
"Şu anda düzinelerce popüler model var, ancak "başarılı çözümlerin" sayısı sınırsız."
"Anlıyorum. Yani birkaç düzine kalıp öğrenmem gerekiyor?"
"Gerçek bir programlama deneyimine sahip olana kadar, sana pek bir şey vermeyecekler."
"Biraz daha deneyim kazansan iyi olur ve bir yıl içinde bu konuya geri dön ve onları daha derinlemesine anlamaya çalış. En az birkaç düzine en popüler tasarım modeli."
"Başkasının deneyimini kullanmamak ve bunun yerine 110. kez bir şey icat etmek günahtır."
"Kabul ediyorum."
"Öyleyse başlayalım."
Adaptör (veya sarıcı) deseni
"Çin'e geldiğinizi ve elektrik prizlerinin farklı bir standartta olduğunu gördüğünüzü hayal edin. Delikler yuvarlak değil düz. Bu durumda bir adaptöre ihtiyacınız olacak."
"Benzer bir şey programlamada da olabilir. Sınıflar benzer ama farklı arayüzlerde çalışır. Bu yüzden aralarında bir adaptör yapmamız gerekiyor."
"Böyle görünüyor:"
interface Time
{
int getSeconds();
int getMinutes();
int getHours();
}
interface TotalTime
{
int getTotalSeconds();
}
"İki arayüzümüz olduğunu varsayalım: Time ve TotalTime ."
"Zaman arabirimi, getSeconds (), getMinutes () ve getHours () yöntemlerini kullanarak geçerli saati almanızı sağlar ."
" TotalTime arayüzü, gece yarısından şimdiki ana kadar geçen saniye sayısını almanızı sağlar."
"Bir TotalTime nesnemiz varsa, ancak bir Time nesnesine ihtiyacımız varsa veya tam tersi olursa ne yapmalıyız ?"
"Bunun için adaptör sınıfları yazabiliriz. Örneğin:"
class TotalTimeAdapter implements Time
{
private TotalTime totalTime;
public TotalTimeAdapter(TotalTime totalTime)
{
this.totalTime = totalTime;
}
int getSeconds()
{
return totalTime.getTotalSeconds() % 60; // seconds
}
int getMinutes()
{
return totalTime.getTotalSeconds() / 60; // minutes
}
int getHours()
{
return totalTime.getTotalSeconds() / (60 * 60); // hours
}
}
TotalTime totalTime = TimeManager.getCurrentTime();
Time time = new TotalTimeAdapter(totalTime);
System.out.println(time.getHours() + " : " + time.getMinutes () + " : " +time.getSeconds());
"Ve diğer yönde bir adaptör:"
class TimeAdapter implements TotalTime
{
private Time time;
public TimeAdapter(Time time)
{
this.time = time;
}
int getTotalSeconds()
{
return time.getHours() * 60 * 60 + time.getMinutes() * 60 + time.getSeconds();
}
}
Time time = new Time();
TotalTime totalTime = new TimeAdapter(time);
System.out.println(time.getTotalSeconds());
"Ah, beğendim. Ama herhangi bir örnek var mı?"
"Elbette! Örnek olarak, InputStreamReader klasik bir bağdaştırıcıdır. Bir InputStream'i Reader'a dönüştürür."
"Bazen bu modele sarmalayıcı da denir, çünkü yeni sınıf başka bir nesneyi 'sarar'."
" Burada başka ilginç şeyler de okuyabilirsiniz ."
proxy kalıbı
"Proxy modeli, sarmalayıcı modeline biraz benzer. Ancak amacı arayüzleri dönüştürmek değil, proxy sınıfı içinde depolanan orijinal nesneye erişimi kontrol etmektir. Ayrıca, hem orijinal sınıf hem de proxy genellikle aynı arayüze sahiptir. bu da orijinal sınıftaki bir nesneyi bir proxy nesnesiyle değiştirmeyi kolaylaştırıyor."
"Örneğin:"
interface Bank
{
public void setUserMoney(User user, double money);
public int getUserMoney(User user);
}
class CitiBank implements Bank
{
public void setUserMoney(User user, double money)
{
UserDAO.updateMoney(user, money);
}
public int getUserMoney(User user)
{
return UserDAO.getMoney(user);
}
}
class BankSecurityProxy implements Bank
{
private Bank bank;
public BankSecurityProxy(Bank bank)
{
this.bank = bank;
}
public void setUserMoney(User user, double money)
{
if (!SecurityManager.authorize(user, BankAccounts.Manager))
throw new SecurityException("User can’t change money value");
bank.setUserMoney(user, money);
}
public int getUserMoney(User user)
{
if (!SecurityManager.authorize(user, BankAccounts.Manager))
throw new SecurityException("User can’t get money value");
return bank.getUserMoney(user);
}
}
"Yukarıdaki örnekte, Banka arayüzünü ve bu arayüzün bir uygulaması olan CitiBank sınıfını tanımladık."
"Arayüz, bir kullanıcının hesap bakiyesini almanızı veya değiştirmenizi sağlar."
Ardından , Bank arayüzünü de uygulayan ve farklı bir Bank arayüzüne referans depolayan BankSecurityProxy'yi yarattık. Bu sınıfın yöntemleri, kullanıcının hesap sahibi mi yoksa banka yöneticisi mi olduğunu kontrol eder. Değilse, bir SecurityException atılır."
"Pratikte şu şekilde çalışıyor:"
User user = AuthManager.authorize(login, password);
Bank bank = BankFactory.createUserBank(user);
bank.setUserMoney(user, 1000000);
User user = AuthManager.authorize(login, password);
Bank bank = BankFactory.createUserBank(user);
bank = new BankSecurityProxy(bank);
bank.setUserMoney(user, 1000000);
"İlk örnekte, bir banka nesnesi oluşturuyoruz ve onun setUserMoney yöntemini çağırıyoruz.
"İkinci örnekte, orijinal banka nesnesini bir BankSecurityProxy nesnesine sardık . Aynı arayüze sahipler, bu nedenle sonraki kod eskisi gibi çalışmaya devam ediyor. Ancak artık bir yöntem her çağrıldığında bir güvenlik kontrolü gerçekleştirilecek."
"Serin!"
"Evet. Bu tür birçok proxy'niz olabilir. Örneğin, hesap bakiyesinin çok büyük olup olmadığını kontrol eden başka bir proxy ekleyebilirsiniz. Banka müdürü kendi hesabına çok para yatırmaya karar verebilir ve fonlarla birlikte Küba'ya kaçabilir. ."
"Dahası... Tüm bu nesne zincirlerinin oluşturulması , ihtiyacınız olanları etkinleştirebileceğiniz/devre dışı bırakabileceğiniz bir BankFactory sınıfına yerleştirilebilir ."
" BufferedReader benzer bir ilke kullanarak çalışır. Bu bir Reader'dır ancak ek iş yapar."
"Bu yaklaşım, çeşitli "parçalardan" gerekli işlevselliğe sahip bir nesneyi "birleştirmenize" olanak tanır."
"Ah, neredeyse unutuyordum. Proxy'ler size az önce gösterdiğimden çok daha yaygın olarak kullanılıyor. Diğer kullanımları buradan okuyabilirsiniz ."
Köprü deseni
"Bazen bir program çalışırken, bir nesnenin işlevselliğini önemli ölçüde değiştirmek gerekir. Örneğin, daha sonra bir büyücü tarafından ejderhaya dönüştürülen eşek karakterli bir oyununuz olduğunu varsayalım. Ejderha tamamen farklı davranış ve özelliklere sahiptir, ancak aynı nesne!"
"Yeni bir nesne yaratıp onunla işimizi bitiremez miyiz?"
"Her zaman değil. Diyelim ki eşeğiniz bir grup karakterle arkadaş, ya da belki birkaç büyünün etkisi altındaydı ya da belirli görevlerde yer aldı. Diğer bir deyişle, nesne zaten birçok yerde kullanılıyor olabilir - ve birçok başka nesneyle bağlantılı. Yani bu durumda, basitçe yeni bir nesne yaratmak bir seçenek değil."
"Peki, o zaman ne yapılabilir?"
"Köprü paterni en başarılı çözümlerden biridir."
"Bu kalıp, bir nesneyi iki nesneye ayırmayı gerektirir: bir "arayüz nesnesi" ve bir "uygulama nesnesi"."
"Arayüz ile onu uygulayan sınıf arasındaki fark nedir?"
"Bir arayüz ve bir sınıfla, tek bir nesne elde ederiz. Ama burada - elimizde iki tane var. Şu örneğe bakın:"
class User
{
private UserImpl realUser;
public User(UserImpl impl)
{
realUser = impl;
}
public void run() //Run
{
realUser.run();
}
public void fly() //Fly
{
realUser.fly();
}
}
class UserImpl
{
public void run()
{
}
public void fly()
{
}
}
"Ve sonra UserImpl'in çeşitli alt sınıflarını, örneğin UserDonkey (eşek) ve UserDragon (ejderha) bildirebilirsiniz ."
"Yine de, bunun nasıl işleyeceğini gerçekten anlamıyorum."
"Şey, bunun gibi bir şey:"
class User
{
private UserImpl realUser;
public User(UserImpl impl)
{
realUser = impl;
}
public void transformToDonkey()
{
realUser = new UserDonkeyImpl();
}
public void transformToDragon()
{
realUser = new UserDragonImpl();
}
}
User user = new User(new UserDonkey()); // Internally, we're a donkey
user.transformToDragon(); // Now we're a dragon internally
"Yani proxy gibi bir şey."
"Evet, ama bir proxy'de ana nesne ayrı bir yerde saklanabilir ve kod bunun yerine proxy'lerle çalışır. Burada herkesin ana nesneyle çalıştığını ama parçalarının dahili olarak değiştiğini söylüyoruz."
"Ah. Teşekkürler. Daha fazla okumam için bana bir bağlantı verir misin?"
"Elbette, dostum, dostum. Buyrun: Köprü modeli ."
GO TO FULL VERSION