Yazılım geliştirmede kalıp: bağdaştırıcı kalıbı
Modern yazılım geliştirmede şablonlar, açıkça tanımlanmış terminoloji ve temiz belgelerle önemli bir soyutlamadır. “Design Patterns: Elements of Reusable Object-Oriented Software” (kısaca Design Patterns) adlı klasik kitap, Adapter modeli dahil 23 model içerir. Temel fikri oldukça basittir: bir arayüzü başka bir arayüze dönüştürür.
Bağdaştırıcı modeli, yazılım geliştiricilerin müşterinin talep ettiği işlevselliği uygulayan bir sınıfa sahip olduğu ancak ilişkili arayüzün şirket politikasıyla tutarsız olduğu durumlarda özellikle kullanışlıdır. Bağdaştırıcı modeli, gerekli arabirimi mevcut sınıfla desteklemeyi kolaylaştırır.
Design Patterns: Elements of Reusable Object-Oriented Software (Tasarım Modelleri: Yeniden Kullanılabilir Nesne Yönelimli Yazılım Öğeleri) kitabında tartışılan tüm modeller arasında, yalnızca sınıf düzeyinde değil, aynı zamanda nesne düzeyinde de uygulanan tek Bağdaştırıcı modelidir.
Bu yapısal modeli uygulamanın iki yaygın yolunu göstermeden önce, temel gerçeklere hızlıca bir göz atalım:
adaptörün modeli
amaç
Ayrıca şöyle bilinir
kullanım durumu
Konteyner adaptörleri std::stack, std::queue Ve std:
riority_queue dizi kapsayıcıları için özel bir arabirim sağlar. Aşağıdaki kod parçacığı, üç kapsayıcı adaptörünün model imzasını gösterir:
template<typename T, typename Container = std::deque<T>>
class stack;
template<typename T, typename Container = std::deque<T>>
class queue;
template<typename T, typename Container = std::vector<T>,
typename Compare = std::less<typename Container::value_type>>
class priority_queue;
Varsayılan olarak sığdır std::stack Ve std::queue içeren dizi std::deque; std:
riority_queue kullanımda std::vector. Ayrıca gerekli std:
riority_queue ikili bir yüklem. std::less varsayılan olarak kullanılır.
C++’ın başka bağdaştırıcıları vardır.
C++, ekleme yineleyicilerini ve akış yineleyicilerini destekler.
Üç ekleme yineleyicisi ile std::front_inserter, std::back_inserter Ve std::inserter bir öğe, bir kapsayıcının başına, sonuna veya herhangi bir yerine yerleştirilebilir.
Akış yineleyici bağdaştırıcıları, akışları bir veri kaynağı veya hedef olarak kullanabilir. C++ sırasıyla istream yineleyicileri ve ostream yineleyicileri oluşturmak için iki işlev sunar. Oluşturulan istream yineleyiciler girdi yineleyiciler gibi, ostream yineleyiciler ise ekleme yineleyiciler gibi davranır.
çerçeve
Aşağıdaki iki sınıf diyagramı, sınıf tabanlı veya nesne tabanlı bağdaştırıcı modelinin yapısını göstermektedir (Kısa olması için bunlara sınıf bağdaştırıcıları ve nesne bağdaştırıcıları diyeceğim).
sınıf adaptörü
nesne bağdaştırıcısı
müşteri
Sınıf:
uygulama
sınıf adaptörü
Aşağıdaki örnekte, sınıf eşleşir RectangleAdapter arayüzü LegacyRectangle üzerinde.
// adapterClass.cpp
#include <iostream>
typedef int Coordinate;
typedef int Dimension;
class Rectangle {
public:
virtual void draw() = 0;
virtual ~Rectangle() = default;
};
class LegacyRectangle {
public:
LegacyRectangle(Coordinate x1, Coordinate y1, Coordinate x2, Coordinate y2) : x1_(x1), y1_(y1), x2_(x2), y2_(y2){
std::cout << "LegacyRectangle: create. (" << x1_ << "," << y1_ << ") => ("
<< x2_ << "," << y2_ << ")" << 'n';
}
void oldDraw() {
std::cout << "LegacyRectangle: oldDraw. (" << x1_ << "," << y1_
<< ") => (" << x2_ << "," << y2_ << ")" << 'n';
}
private:
Coordinate x1_;
Coordinate y1_;
Coordinate x2_;
Coordinate y2_;
};
class RectangleAdapter : public Rectangle, private LegacyRectangle {
public:
RectangleAdapter(Coordinate x, Coordinate y, Dimension w, Dimension h) : LegacyRectangle(x, y, x + w, y + h) { // (1)
std::cout << "RectangleAdapter: create. (" << x << "," << y
<< "), width = " << w << ", height = " << h << 'n';
}
void draw() override {
oldDraw();
std::cout << "RectangleAdapter: draw." << 'n';
}
};
int main() {
std::cout << 'n';
Rectangle* r = new RectangleAdapter(120, 200, 60, 40);
r->draw();
delete r;
std::cout << 'n';
}
RectangleAdapter çoklu kalıtım sayesinde teşekkürler arayüzüne sahiptir Rectangle ve uygulanması LegacyRectangle. Artı, yakışıyor RectangleAdapter boyutu LegacyRectangle yukarı (satır 1).
Bağdaştırıcı modelinin bu uygulaması, özel kalıtımın nadir kullanım durumlarından biridir. Buna arayüz kalıtımı ve uygulama kalıtımı hakkında birkaç kelime eklemek istiyorum:
nesne bağdaştırıcısı
Aşağıdaki uygulama, RectangleAdapterçağrıları bağdaştırıcısına devret LegacyRectangle.
// adapterObject.cpp
#include <iostream>
typedef int Coordinate;
typedef int Dimension;
class LegacyRectangle {
public:
LegacyRectangle(Coordinate x1, Coordinate y1, Coordinate x2, Coordinate y2) : x1_(x1), y1_(y1), x2_(x2), y2_(y2){
std::cout << "LegacyRectangle: create. (" << x1_ << "," << y1_ << ") => ("
<< x2_ << "," << y2_ << ")" << 'n';
}
void oldDraw() {
std::cout << "LegacyRectangle: oldDraw. (" << x1_ << "," << y1_
<< ") => (" << x2_ << "," << y2_ << ")" << 'n';
}
private:
Coordinate x1_;
Coordinate y1_;
Coordinate x2_;
Coordinate y2_;
};
class RectangleAdapter {
public:
RectangleAdapter(Coordinate x, Coordinate y, Dimension w, Dimension h) : legacyRectangle{LegacyRectangle(x, y, x + w, y + h)} { // (1)
std::cout << "RectangleAdapter: create. (" << x << "," << y
<< "), width = " << w << ", height = " << h << 'n';
}
void draw() {
legacyRectangle.oldDraw();
std::cout << "RectangleAdapter: draw." << 'n';
}
private:
LegacyRectangle legacyRectangle;
};
int main() {
std::cout << 'n';
RectangleAdapter r(120, 200, 60, 40);
r.draw();
std::cout << 'n';
}
Sınıf RectangleAdapter sen yarat LegacyRectangle doğrudan yapıcılarında (satır 1). Başka bir olasılık da şu olurdu: LegacyRectangle yapıcı parametresi olarak RectangleAdapter kullanmak.
class RectangleAdapter {
public:
RectangleAdapter(const LegacyRectangle& legRec): legacyRectangle{legRec} {}
...
};
Bu programın çıktısı bir öncekiyle aynıdır.
İlgili tasarım desenleri
Sınıf bağdaştırıcısına karşı nesne bağdaştırıcısı
Sınıf bağdaştırıcısı, sınıfları ve alt sınıflarını zorlar. Arayüz, uygulama ve sanal işlev çağrılarının ayrılmasını kullanın. İşlevselliği sabit kodlanmıştır ve derleme zamanında kullanılabilir. Sınıf bağdaştırıcısı daha az esneklik sunar ve nesne bağdaştırıcısı gibi dinamik davranışlardan yoksundur.
Nesne bağdaştırıcısı, nesne ilişkisini kullanır. Soyutlama, nesneleri bir araya getirerek ve işlerini devrederek oluşturulabilir. Bu kompozisyon çalışma zamanında yapılabilir. Sonuç olarak, bir nesne bağdaştırıcısı daha esnektir ve çalışma zamanında delege nesnesinin değiştirilmesine izin verir.
Sıradaki ne?
Köprü modeli, arabirimi uygulamasından ayırmaya yardımcı olur. Bir sonraki yazımda daha detaylı olarak sunacağım.
(harita)
Haberin Sonu
Yazılım geliştirmede kalıp: bağdaştırıcı kalıbı
Modern yazılım geliştirmede şablonlar, açıkça tanımlanmış terminoloji ve temiz belgelerle önemli bir soyutlamadır. “Design Patterns: Elements of Reusable Object-Oriented Software” (kısaca Design Patterns) adlı klasik kitap, Adapter modeli dahil 23 model içerir. Temel fikri oldukça basittir: bir arayüzü başka bir arayüze dönüştürür.

Bağdaştırıcı modeli, yazılım geliştiricilerin müşterinin talep ettiği işlevselliği uygulayan bir sınıfa sahip olduğu ancak ilişkili arayüzün şirket politikasıyla tutarsız olduğu durumlarda özellikle kullanışlıdır. Bağdaştırıcı modeli, gerekli arabirimi mevcut sınıfla desteklemeyi kolaylaştırır.
Design Patterns: Elements of Reusable Object-Oriented Software (Tasarım Modelleri: Yeniden Kullanılabilir Nesne Yönelimli Yazılım Öğeleri) kitabında tartışılan tüm modeller arasında, yalnızca sınıf düzeyinde değil, aynı zamanda nesne düzeyinde de uygulanan tek Bağdaştırıcı modelidir.
Bu yapısal modeli uygulamanın iki yaygın yolunu göstermeden önce, temel gerçeklere hızlıca bir göz atalım:
adaptörün modeli
amaç
- Bir arayüzü diğerine çevir
Ayrıca şöyle bilinir
kullanım durumu
- Bir sınıf gerekli arabirime sahip değil
- Bir dizi benzer sınıf için genel bir arayüzün tanımı
Konteyner adaptörleri std::stack, std::queue Ve std:
template<typename T, typename Container = std::deque<T>>
class stack;
template<typename T, typename Container = std::deque<T>>
class queue;
template<typename T, typename Container = std::vector<T>,
typename Compare = std::less<typename Container::value_type>>
class priority_queue;
Varsayılan olarak sığdır std::stack Ve std::queue içeren dizi std::deque; std:
C++’ın başka bağdaştırıcıları vardır.
C++, ekleme yineleyicilerini ve akış yineleyicilerini destekler.
Üç ekleme yineleyicisi ile std::front_inserter, std::back_inserter Ve std::inserter bir öğe, bir kapsayıcının başına, sonuna veya herhangi bir yerine yerleştirilebilir.
Akış yineleyici bağdaştırıcıları, akışları bir veri kaynağı veya hedef olarak kullanabilir. C++ sırasıyla istream yineleyicileri ve ostream yineleyicileri oluşturmak için iki işlev sunar. Oluşturulan istream yineleyiciler girdi yineleyiciler gibi, ostream yineleyiciler ise ekleme yineleyiciler gibi davranır.
çerçeve
Aşağıdaki iki sınıf diyagramı, sınıf tabanlı veya nesne tabanlı bağdaştırıcı modelinin yapısını göstermektedir (Kısa olması için bunlara sınıf bağdaştırıcıları ve nesne bağdaştırıcıları diyeceğim).
sınıf adaptörü

nesne bağdaştırıcısı

müşteri
- Üye işlevini kullanın methodA() adaptörün
Sınıf:
- işlevselliği sağlar methodA() çoklu kalıtım yoluyla kullanılabilir
- itibaren halka açık olacak Interface ve özel Implementation türev
- Üye fonksiyon çağrısını kendi Adaptee
- İstemci işlevselliğini uygular
uygulama
sınıf adaptörü
Aşağıdaki örnekte, sınıf eşleşir RectangleAdapter arayüzü LegacyRectangle üzerinde.
// adapterClass.cpp
#include <iostream>
typedef int Coordinate;
typedef int Dimension;
class Rectangle {
public:
virtual void draw() = 0;
virtual ~Rectangle() = default;
};
class LegacyRectangle {
public:
LegacyRectangle(Coordinate x1, Coordinate y1, Coordinate x2, Coordinate y2) : x1_(x1), y1_(y1), x2_(x2), y2_(y2){
std::cout << "LegacyRectangle: create. (" << x1_ << "," << y1_ << ") => ("
<< x2_ << "," << y2_ << ")" << 'n';
}
void oldDraw() {
std::cout << "LegacyRectangle: oldDraw. (" << x1_ << "," << y1_
<< ") => (" << x2_ << "," << y2_ << ")" << 'n';
}
private:
Coordinate x1_;
Coordinate y1_;
Coordinate x2_;
Coordinate y2_;
};
class RectangleAdapter : public Rectangle, private LegacyRectangle {
public:
RectangleAdapter(Coordinate x, Coordinate y, Dimension w, Dimension h) : LegacyRectangle(x, y, x + w, y + h) { // (1)
std::cout << "RectangleAdapter: create. (" << x << "," << y
<< "), width = " << w << ", height = " << h << 'n';
}
void draw() override {
oldDraw();
std::cout << "RectangleAdapter: draw." << 'n';
}
};
int main() {
std::cout << 'n';
Rectangle* r = new RectangleAdapter(120, 200, 60, 40);
r->draw();
delete r;
std::cout << 'n';
}
RectangleAdapter çoklu kalıtım sayesinde teşekkürler arayüzüne sahiptir Rectangle ve uygulanması LegacyRectangle. Artı, yakışıyor RectangleAdapter boyutu LegacyRectangle yukarı (satır 1).
Bağdaştırıcı modelinin bu uygulaması, özel kalıtımın nadir kullanım durumlarından biridir. Buna arayüz kalıtımı ve uygulama kalıtımı hakkında birkaç kelime eklemek istiyorum:
- the arayüz kalıtımı genel mirası kullanın. Temel sınıfın kullanıcılarını etkilemeden türetilmiş sınıfların eklenebilmesi ve değiştirilebilmesi için kullanıcıları uygulamadan ayırın. Türetilmiş sınıflar, temel sınıf arayüzünü destekler.
- İçinde uygulama mirası özel miras sıklıkla kullanılır. Tipik olarak, türetilmiş sınıf, temel sınıfın işlevselliğini uyarlayarak kendi işlevselliğini sağlar. Türetilmiş sınıflar, temel sınıf arayüzünü desteklemez.

nesne bağdaştırıcısı
Aşağıdaki uygulama, RectangleAdapterçağrıları bağdaştırıcısına devret LegacyRectangle.
// adapterObject.cpp
#include <iostream>
typedef int Coordinate;
typedef int Dimension;
class LegacyRectangle {
public:
LegacyRectangle(Coordinate x1, Coordinate y1, Coordinate x2, Coordinate y2) : x1_(x1), y1_(y1), x2_(x2), y2_(y2){
std::cout << "LegacyRectangle: create. (" << x1_ << "," << y1_ << ") => ("
<< x2_ << "," << y2_ << ")" << 'n';
}
void oldDraw() {
std::cout << "LegacyRectangle: oldDraw. (" << x1_ << "," << y1_
<< ") => (" << x2_ << "," << y2_ << ")" << 'n';
}
private:
Coordinate x1_;
Coordinate y1_;
Coordinate x2_;
Coordinate y2_;
};
class RectangleAdapter {
public:
RectangleAdapter(Coordinate x, Coordinate y, Dimension w, Dimension h) : legacyRectangle{LegacyRectangle(x, y, x + w, y + h)} { // (1)
std::cout << "RectangleAdapter: create. (" << x << "," << y
<< "), width = " << w << ", height = " << h << 'n';
}
void draw() {
legacyRectangle.oldDraw();
std::cout << "RectangleAdapter: draw." << 'n';
}
private:
LegacyRectangle legacyRectangle;
};
int main() {
std::cout << 'n';
RectangleAdapter r(120, 200, 60, 40);
r.draw();
std::cout << 'n';
}
Sınıf RectangleAdapter sen yarat LegacyRectangle doğrudan yapıcılarında (satır 1). Başka bir olasılık da şu olurdu: LegacyRectangle yapıcı parametresi olarak RectangleAdapter kullanmak.
class RectangleAdapter {
public:
RectangleAdapter(const LegacyRectangle& legRec): legacyRectangle{legRec} {}
...
};
Bu programın çıktısı bir öncekiyle aynıdır.
İlgili tasarım desenleri
- Köprü modeli, Nesne Bağdaştırıcısına benzer, ancak farklı bir amaca sahiptir. Köprü modelinin amacı arayüzü uygulamadan ayırmak iken adaptörün amacı mevcut bir arayüzü değiştirmektir.
- Dekoratör deseni, arayüzünü değiştirmeden bir nesneyi genişletir. Dekoratörler birbirine geçebilir, ancak köprüler veya bağdaştırıcılar birbirine kenetlenemez.
- Proxy modeli, temsil ettiği nesnenin uygulamasını genişletir ancak arayüzünü değiştirmez.
Sınıf bağdaştırıcısına karşı nesne bağdaştırıcısı
Sınıf bağdaştırıcısı, sınıfları ve alt sınıflarını zorlar. Arayüz, uygulama ve sanal işlev çağrılarının ayrılmasını kullanın. İşlevselliği sabit kodlanmıştır ve derleme zamanında kullanılabilir. Sınıf bağdaştırıcısı daha az esneklik sunar ve nesne bağdaştırıcısı gibi dinamik davranışlardan yoksundur.
Nesne bağdaştırıcısı, nesne ilişkisini kullanır. Soyutlama, nesneleri bir araya getirerek ve işlerini devrederek oluşturulabilir. Bu kompozisyon çalışma zamanında yapılabilir. Sonuç olarak, bir nesne bağdaştırıcısı daha esnektir ve çalışma zamanında delege nesnesinin değiştirilmesine izin verir.
Sıradaki ne?
Köprü modeli, arabirimi uygulamasından ayırmaya yardımcı olur. Bir sonraki yazımda daha detaylı olarak sunacağım.
(harita)
Haberin Sonu