CodeGym /Java Blogu /Rastgele /Bağdaştırıcı tasarım deseni hangi sorunları çözer?
John Squirrels
Seviye
San Francisco

Bağdaştırıcı tasarım deseni hangi sorunları çözer?

grupta yayınlandı
Birlikte çalışması gereken uyumsuz bileşenler yazılım geliştirmeyi zorlaştırır. Örneğin, yeni bir kütüphaneyi Java'nın önceki sürümlerinde yazılmış eski bir platformla entegre etmeniz gerekirse, uyumsuz nesnelerle veya daha doğrusu uyumsuz arayüzlerle karşılaşabilirsiniz. Bağdaştırıcı tasarım deseni hangi sorunları çözer?  - 1Bu durumda ne yapmalı? Kodu yeniden yaz? Bunu yapamıyoruz çünkü sistemi analiz etmek çok zaman alacak veya uygulamanın iç mantığı bozulacak. Bu sorunu çözmek için adaptör modeli oluşturuldu. Uyumsuz arayüzlere sahip nesnelerin birlikte çalışmasına yardımcı olur. Nasıl kullanılacağını görelim!

Sorun hakkında daha fazla bilgi

İlk olarak, eski sistemin davranışını simüle edeceğiz. İşe veya okula geç kalmak için bahaneler ürettiğini varsayalım. Bunu yapmak için, , ve yöntemleri Excuseolan bir arayüze sahiptir . generateExcuse()likeExcuse()dislikeExcuse()

public interface Excuse {
   String generateExcuse();
   void likeExcuse(String excuse);
   void dislikeExcuse(String excuse);
}
Sınıf WorkExcusebu arabirimi uygular:

public class WorkExcuse implements Excuse {
   private String[] excuses = {"in an incredible confluence of circumstances, I ran out of hot water and had to wait until sunlight, focused using a magnifying glass, heated a mug of water so that I could wash.",
   "the artificial intelligence in my alarm clock failed me, waking me up an hour earlier than normal. Because it is winter, I thought it was still nighttime and I fell back asleep. Everything after that is a bit hazy.",
   "my pre-holiday mood slows metabolic processes in my body, leading to depression and insomnia."};
   private String [] apologies = {"This will not happen again, of course. I'm very sorry.", "I apologize for my unprofessional behavior.", "There is no excuse for my actions. I am not worthy of this position."};

   @Override
   public String generateExcuse() { // Randomly select an excuse from the array
       String result = "I was late today because " + excuses[(int) Math.round(Math.random() + 1)] + "\\n" +
               apologies[(int) Math.round(Math.random() + 1)];
       return result;
   }

   @Override
   public void likeExcuse(String excuse) {
       // Duplicate the element in the array so that its chances of being chosen are higher
   }

   @Override
   public void dislikeExcuse(String excuse) {
       // Remove the item from the array
   }
}
Örneğimizi test edelim:

Excuse excuse = new WorkExcuse();
System.out.println(excuse.generateExcuse());
Çıktı:

"I was late today because my pre-holiday mood slows metabolic processes in my body, leading to depression and insomnia.
I apologize for my unprofessional behavior.
Şimdi, bahane üreten bir hizmet başlattığınızı, istatistik topladığınızı ve kullanıcılarınızın çoğunun üniversite öğrencileri olduğunu fark ettiğinizi hayal edin. Bu gruba daha iyi hizmet verebilmek için başka bir geliştiriciden üniversite öğrencilerine özel mazeret üreten bir sistem oluşturmasını istediniz. Geliştirme ekibi pazar araştırması yürüttü, mazeretleri sıraladı, bazı yapay zekalarla bağlantı kurdu ve hizmeti trafik raporları, hava durumu raporları vb. ile entegre etti. Artık üniversite öğrencilerine mazeret üretmek için bir kitaplığınız var ama onun farklı bir arayüzü var: StudentExcuse.

public interface StudentExcuse {
   String generateExcuse();
   void dislikeExcuse(String excuse);
}
Bu arayüzün iki yöntemi vardır: generateExcusebir mazeret oluşturan , ve dislikeExcusemazeretin gelecekte tekrar ortaya çıkmasını engelleyen . Üçüncü taraf kitaplığı düzenlenemez, yani kaynak kodunu değiştiremezsiniz. Şimdi sahip olduğumuz, arayüzü uygulayan iki sınıflı bir sistem Excuseve arayüzü SuperStudentExcuseuygulayan bir sınıfa sahip bir kitaplıktır StudentExcuse:

public class SuperStudentExcuse implements StudentExcuse {
   @Override
   public String generateExcuse() {
       // Logic for the new functionality
       return "An incredible excuse adapted to the current weather conditions, traffic jams, or delays in public transport schedules.";
   }

   @Override
   public void dislikeExcuse(String excuse) {
       // Adds the reason to a blacklist
   }
}
Kod değiştirilemez. Geçerli sınıf hiyerarşisi şöyle görünür: Bağdaştırıcı tasarım deseni hangi sorunları çözer?  - 2Sistemin bu sürümü yalnızca Excuse arabirimiyle çalışır. Kodu yeniden yazamazsınız: büyük bir uygulamada bu tür değişiklikler yapmak uzun bir süreç haline gelebilir veya uygulamanın mantığını bozabilir. Bir temel arayüz tanıtabilir ve hiyerarşiyi genişletebiliriz: Bağdaştırıcı tasarım deseni hangi sorunları çözer?  - 3Bunu yapmak için arayüzü yeniden adlandırmalıyız Excuse. Ancak ciddi uygulamalarda fazladan hiyerarşi istenmez: ortak bir kök öğenin eklenmesi mimariyi bozar. Hem yeni hem de eski işlevselliği minimum kayıpla kullanmamıza izin verecek bir ara sınıf uygulamalısınız. Kısacası bir adaptöre ihtiyacınız var .

Bağdaştırıcı modelinin arkasındaki ilke

Bağdaştırıcı, bir nesnenin yöntem çağrılarının başka bir nesne tarafından anlaşılmasını sağlayan bir ara nesnedir. Örneğimiz için bir bağdaştırıcı uygulayalım ve buna Middleware. Bağdaştırıcımız, nesnelerden biriyle uyumlu bir arabirim uygulamalıdır. Olsun Excuse. Bu, Middlewareilk nesnenin yöntemlerini çağırmaya izin verir. Middlewarearamaları alır ve uyumlu bir şekilde ikinci nesneye iletir. İşte and Middlewareyöntemleriyle uygulama : generateExcusedislikeExcuse

public class Middleware implements Excuse { // 1. Middleware becomes compatible with WorkExcuse objects via the Excuse interface

   private StudentExcuse superStudentExcuse;

   public Middleware(StudentExcuse excuse) { // 2. Get a reference to the object being adapted
       this.superStudentExcuse = excuse;
   }

   @Override
   public String generateExcuse() {
       return superStudentExcuse.generateExcuse(); // 3. The adapter implements an interface method
   }

    @Override
    public void dislikeExcuse(String excuse) {
        // The method first adds the excuse to the blacklist,
        // Then passes it to the dislikeExcuse method of the superStudentExcuse object.
    }
   // The likeExcuse method will appear later
}
Test (müşteri kodunda):

public class Test {
   public static void main(String[] args) {
       Excuse excuse = new WorkExcuse(); // We create objects of the classes
       StudentExcuse newExcuse = new SuperStudentExcuse(); // that must be compatible.
       System.out.println("An ordinary excuse for an employee:");
       System.out.println(excuse.generateExcuse());
       System.out.println("\n");
       Excuse adaptedStudentExcuse = new Middleware(newExcuse); // Wrap the new functionality in the adapter object
       System.out.println("Using new functionality with the adapter:");
       System.out.println(adaptedStudentExcuse.generateExcuse()); // The adapter calls the adapted method
   }
}
Çıktı:

An ordinary excuse for an employee:
I was late today because my pre-holiday mood slows metabolic processes in my body, leading to depression and insomnia.
There is no excuse for my actions. I am not worthy of this position. Using new functionality with the adapter:
Mevcut hava koşullarına, trafik sıkışıklığına veya toplu taşıma programlarındaki gecikmelere uyarlanmış inanılmaz bir bahane. Yöntem generateExcuse, herhangi bir ek değişiklik olmaksızın çağrıyı başka bir nesneye iletir. Yöntem dislikeExcuse, önce bahaneyi kara listeye almamızı gerektirdi. Ara veri işlemeyi gerçekleştirme yeteneği, insanların adaptör modelini sevmesinin bir nedenidir. Peki ya likeExcusearayüzün parçası olan Excuseama arayüzün parçası olmayan yöntem StudentExcuse? Yeni işlevsellik bu işlemi desteklemiyor. UnsupportedOperationExceptionBu durum için icat edildi . İstenen işlem desteklenmiyorsa atılır. Hadi kullanalım. MiddlewareSınıfın yeni uygulaması şöyle görünür:

public class Middleware implements Excuse {

   private StudentExcuse superStudentExcuse;

   public Middleware(StudentExcuse excuse) {
       this.superStudentExcuse = excuse;
   }

   @Override
   public String generateExcuse() {
       return superStudentExcuse.generateExcuse();
   }

   @Override
   public void likeExcuse(String excuse) {
       throw new UnsupportedOperationException("The likeExcuse method is not supported by the new functionality");
   }

   @Override
   public void dislikeExcuse(String excuse) {
       // The method accesses a database to fetch additional information,
       // and then passes it to the superStudentExcuse object's dislikeExcuse method.
   }
}
İlk bakışta bu çözüm pek iyi görünmüyor, ancak işlevselliği taklit etmek durumu karmaşıklaştırabilir. Müşteri dikkat ederse ve bağdaştırıcı iyi belgelenmişse, böyle bir çözüm kabul edilebilir.

Bir adaptör ne zaman kullanılır?

  1. Bir üçüncü taraf sınıfı kullanmanız gerektiğinde, ancak arabirimi ana uygulamayla uyumsuz olduğunda. Yukarıdaki örnek, aramaları hedef nesnenin anlayabileceği bir biçimde saran bir bağdaştırıcı nesnesinin nasıl oluşturulacağını gösterir.

  2. Birkaç mevcut alt sınıf bazı ortak işlevlere ihtiyaç duyduğunda. Ek alt sınıflar oluşturmak yerine (bu, kodun tekrarlanmasına yol açacaktır), bir adaptör kullanmak daha iyidir.

Avantajlar ve dezavantajlar

Avantaj: Bağdaştırıcı, bir nesneden diğerine isteklerin işlenmesinin ayrıntılarını istemciden gizler. İstemci kodu, verileri biçimlendirmeyi veya hedef yönteme yapılan çağrıları işlemeyi düşünmez. Çok karmaşık ve programcılar tembel :) Dezavantaj: Projenin kod tabanı, ek sınıflar nedeniyle karmaşık. Çok sayıda uyumsuz arayüzünüz varsa, ek sınıfların sayısı yönetilemez hale gelebilir.

Bir adaptörü bir cephe veya dekoratörle karıştırmayın

Sadece yüzeysel bir inceleme ile bir adaptör, cephe ve dekoratör desenleriyle karıştırılabilir. Adaptör ile cephe arasındaki fark, cephenin yeni bir arayüz sunması ve tüm alt sistemi sarmasıdır. Ve bir dekoratör, bir bağdaştırıcıdan farklı olarak, arabirim yerine nesnenin kendisini değiştirir.

Adım adım algoritma

  1. Öncelikle, bu modelin çözebileceği bir sorununuz olduğundan emin olun.

  2. Uyumsuz nesnelerle dolaylı olarak etkileşimde bulunmak için kullanılacak istemci arabirimini tanımlayın.

  3. Bağdaştırıcı sınıfının önceki adımda tanımlanan arabirimi devralmasını sağlayın.

  4. Bağdaştırıcı sınıfında, uyarlanan nesneye bir başvuru depolamak için bir alan oluşturun. Bu referans yapıcıya iletilir.

  5. Bağdaştırıcıdaki tüm istemci arabirimi yöntemlerini uygulayın. Bir yöntem şunları yapabilir:

    • Aramaları herhangi bir değişiklik yapmadan iletin

    • Verileri değiştirin veya tamamlayın, hedef yönteme yapılan çağrıların sayısını artırın/azaltın, vb.

    • Aşırı durumlarda, belirli bir yöntem uyumsuz kalırsa, bir UnsupportedOperationException oluşturun. Desteklenmeyen işlemler kesinlikle belgelenmelidir.

  6. Uygulama, istemci arabirimi aracılığıyla yalnızca bağdaştırıcı sınıfını kullanıyorsa (yukarıdaki örnekte olduğu gibi), bağdaştırıcı gelecekte zahmetsizce genişletilebilir.

Tabii ki, bu tasarım deseni her derde deva değildir, ancak farklı arayüzlere sahip nesneler arasındaki uyumsuzluk sorununu zarif bir şekilde çözmenize yardımcı olabilir. Temel kalıpları bilen bir geliştirici, yalnızca algoritma yazmayı bilenlerden birkaç adım öndedir, çünkü ciddi uygulamalar oluşturmak için tasarım kalıpları gerekir. Kodun yeniden kullanımı o kadar zor değil ve bakım keyifli hale geliyor. Hepsi bugün için! Ama yakında çeşitli tasarım modellerini tanımaya devam edeceğiz :)
Yorumlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION