Yazılım geliştirmede kalıplar: boş nesne tasarım kalıbı

Adanali

Active member
Yazılım geliştirmede kalıplar: boş nesne tasarım kalıbı


  1. Yazılım geliştirmede kalıplar: boş nesne tasarım kalıbı

Boş bir nesne, bir nesnenin içinde hiçbir şey yapmama davranışını kapsar. Boş bir nesne kullanmak genellikle çok uygundur.







Rainer Grimm, uzun yıllardır yazılım mimarı, ekip lideri ve eğitim yöneticisi olarak çalışmaktadır. C++, Python ve Haskell programlama dilleri üzerine makaleler yazmaktan hoşlanır, aynı zamanda sık sık uzmanlık konferanslarında konuşmaktan da keyif alır. Modernes C++ blogunda yoğun bir şekilde C++ tutkusundan bahsediyor.







Boş bir nesne

  • hiçbir şey yapmama davranışını bir nesnenin içine alır,
  • koşullu mantık e olmadan iş akışını destekler
  • özel kullanım durumlarını kullanıcıdan gizler.
Dürüst olmak gerekirse, boş nesne hakkında yazacak çok şey yok. Bu yüzden null nesnesini kullanarak bir örnek sunmak istiyorum.

stratejik kapanış


Eşzamanlılık gibi çeşitli alanlarda kullanılacak bir kitaplık uyguladığınızı varsayalım. Güvenli tarafta olmak için kritik bölümleri bir asma kilitle emniyete alın. Kitaplık artık tek iş parçacıklı bir ortamda kullanılıyorsa, gerekmeyen pahalı bir eşitleme mekanizması uygulandığından bir performans sorunu vardır. Bu durumda, stratejik engelleme yardımcı olur.

Strateji engelleme, strateji modelinin bloklara uygulanmasıdır. Bu, kilitleme stratejisini bir nesneye yerleştirmek ve onu sistemin değiştirilebilir bir bileşeni yapmak anlamına gelir.


Stratejik kilitlemeyi uygulamanın iki tipik yolu vardır: çalışma zamanı polimorfizmi (nesne oryantasyonu) veya derleme zamanı polimorfizmi (şablonlar).

Her iki mod da kapatma stratejisinin özelleştirilmesini ve genişletilmesini geliştirir, sistem bakımını basitleştirir ve bileşenlerin yeniden kullanımını destekler. Ayrıca, çalışma zamanı ile derleme zamanı kilitleme stratejisinin uygulamaları birkaç açıdan farklılık gösterir.

Avantajlar

  • çalışma zamanında engelleme stratejisini yapılandırmanıza izin verir,
  • nesne yönelimli bir geçmişe sahip geliştiriciler için anlaşılması daha kolaydır.
  • derleme zamanı polimorfizmi
  • ek çalışma zamanı maliyeti yoktur,
  • düz hiyerarşilere sahiptir.
Dezavantajları

  • ek bir işaretçiye veya dolaylı yönlendirmeye ihtiyaç duyar,
  • derin bir türetme hiyerarşisi oluşturabilir.
  • derleme zamanı polimorfizmi
  • çok ayrıntılı hata mesajları üretebilir.
Çalışma zamanı polimorfizmine dayalı uygulama


program strategizedLockingRuntime.cpp üç farklı muteks sunar.


// strategizedLockingRuntime.cpp

#include <iostream>
#include <mutex>
#include <shared_mutex>

class Lock {
public:
virtual void lock() const = 0;
virtual void unlock() const = 0;
};

class StrategizedLocking {
Lock& lock; // (1)
public:
StrategizedLocking(Lock& l): lock(l){
lock.lock(); // (2)
}
~StrategizedLocking(){
lock.unlock(); // (3)
}
};

struct NullObjectMutex{
void lock(){}
void unlock(){}
};

class NoLock : public Lock { // (4)
void lock() const override {
std::cout << "NoLock:🔒 " << 'n';
nullObjectMutex.lock();
}
void unlock() const override {
std::cout << "NoLock:🔓 " << 'n';
nullObjectMutex.unlock();
}
mutable NullObjectMutex nullObjectMutex; // (9)
};

class ExclusiveLock : public Lock { // (5)
void lock() const override {
std::cout << " ExclusiveLock:🔒 " << 'n';
mutex.lock();
}
void unlock() const override {
std::cout << " ExclusiveLock:🔓 " << 'n';
mutex.unlock();
}
mutable std::mutex mutex; // (10)
};

class SharedLock : public Lock { // (6)
void lock() const override {
std::cout << " SharedLock::lock_shared: " << 'n';
sharedMutex.lock_shared(); // (7)
}
void unlock() const override {
std::cout << " SharedLock::unlock_shared: " << 'n';
sharedMutex.unlock_shared(); // (8)
}
mutable std::shared_mutex sharedMutex; // (11)
};

int main() {

std::cout << 'n';

NoLock noLock;
StrategizedLocking stratLock1{noLock};

{
ExclusiveLock exLock;
StrategizedLocking stratLock2{exLock};
{
SharedLock sharLock;
StrategizedLocking startLock3{sharLock};
}
}

std::cout << 'n';

}


Sınıf StrategizedLocking bir asma kilide (1) sahiptir. StrategizedLocking kapsamlı kilitlemeyi modeller ve ardından yapıcıdaki (2) muteksi kilitler ve yıkıcıda (3) tekrar kilidini açar. Lock soyut bir sınıftır ve türetilmiş tüm sınıfların arayüzünü tanımlar. bunlar sınıflar NoLock (4), ExclusiveLock (5) ve SharedLock (6). SharedLock aramalar lock_shared (7) ve unlock_shared (8) onun üzerinde std::shared_mutex AÇIK. Bu blokların her biri mutekslerden birine sahiptir. NullObjectMutex (9), std::mutex (10) veya std::shared_mutex (11). NullObjectMutex noop yer tutucudur. Muteksler değişken olarak bildirilir. Yani onlar gibi sabit üye fonksiyonlarındalar. lock VE unlock kullanılabilir

Derleme zamanı polimorfizmine dayalı uygulama


Şablon tabanlı uygulama, nesne yönelimli uygulamaya çok benzer.


// strategizedLockingCompileTime.cpp

#include <iostream>
#include <mutex>
#include <shared_mutex>


template <typename Lock>
class StrategizedLocking {
Lock& lock;
public:
StrategizedLocking(Lock& l): lock(l){
lock.lock();
}
~StrategizedLocking(){
lock.unlock();
}
};

struct NullObjectMutex {
void lock(){}
void unlock(){}
};

class NoLock{ // (1)
public:
void lock() const {
std::cout << "NoLock:🔒 " << 'n';
nullObjectMutex.lock();
}
void unlock() const {
std::cout << "NoLock:🔓 " << 'n';
nullObjectMutex.lock();
}
mutable NullObjectMutex nullObjectMutex;
};

class ExclusiveLock { // (2)
public:
void lock() const {
std::cout << " ExclusiveLock:🔒 " << 'n';
mutex.lock();
}
void unlock() const {
std::cout << " ExclusiveLock:🔓 " << 'n';
mutex.unlock();
}
mutable std::mutex mutex;
};

class SharedLock { // (3)
public:
void lock() const {
std::cout << " SharedLock::lock_shared: " << 'n';
sharedMutex.lock_shared();
}
void unlock() const {
std::cout << " SharedLock::unlock_shared: " << 'n';
sharedMutex.unlock_shared();
}
mutable std::shared_mutex sharedMutex;
};

int main() {

std::cout << 'n';

NoLock noLock;
StrategizedLocking<NoLock> stratLock1{noLock};

{
ExclusiveLock exLock;
StrategizedLocking<ExclusiveLock> stratLock2{exLock};
{
SharedLock sharLock;
StrategizedLocking<SharedLock> startLock3{sharLock};
}
}

std::cout << 'n';

}



Programlar strategizedLockingRuntime.cpp VE strategizedLockingCompileTime.cpp aynı sonucu üret:








kilitler NoLock (1), ExclusiveLock (2) ve SharedLock (3) soyut bir temel sınıfları yoktur. Bunun şu sonucu var StrategizedLocking doğru arabirimi desteklemeyen bir nesneyle başlatılabilir. Bu örnekleme, kaçınılmaz olarak bir derleme zamanı hatasına yol açar. Bu boşluk, C++20’de kavramlarla zarif bir şekilde kapatılabilir.

Kavram BasicLockable


Yerine template <typename Lock> class StrategizedLocking kavram BasicLockable: template <BasicLockable Lock> class StrategizedLocking kullanım. Bu, kullanılan tüm kilitlerin Kavramlar olduğu anlamına gelir. BasicLockable desteklemek zorunda. Kavram, adlandırılmış bir gereksinimdir ve birçok kavram, C++20 Kavram Kitaplığı’nda zaten tanımlanmıştır. Kavram BasicLockable yalnızca C++20 standardının metninde kullanılır. Bu nedenle kavramı tanımlar ve kullanırım BasicLockable strateji bloğunun aşağıdaki geliştirilmiş derleme zamanı uygulamasında.


// strategizedLockingCompileTimeWithConcepts.cpp

#include <iostream>
#include <mutex>
#include <shared_mutex>

template <typename T> // (1)
concept BasicLockable = requires(T lo) {
lo.lock();
lo.unlock();
};

template <BasicLockable Lock> // (2)
class StrategizedLocking {
Lock& lock;
public:
StrategizedLocking(Lock& l): lock(l){
lock.lock();
}
~StrategizedLocking(){
lock.unlock();
}
};

struct NullObjectMutex {
void lock(){}
void unlock(){}
};

class NoLock{
public:
void lock() const {
std::cout << "NoLock:🔒 " << 'n';
nullObjectMutex.lock();
}
void unlock() const {
std::cout << "NoLock:🔓 " << 'n';
nullObjectMutex.lock();
}
mutable NullObjectMutex nullObjectMutex;
};

class ExclusiveLock {
public:
void lock() const {
std::cout << " ExclusiveLock:🔒 " << 'n';
mutex.lock();
}
void unlock() const {
std::cout << " ExclusiveLock:🔓 " << 'n';
mutex.unlock();
}
mutable std::mutex mutex;
};

class SharedLock {
public:
void lock() const {
std::cout << " SharedLock::lock_shared: " << 'n';
sharedMutex.lock_shared();
}
void unlock() const {
std::cout << " SharedLock::unlock_shared: " << 'n';
sharedMutex.unlock_shared();
}
mutable std::shared_mutex sharedMutex;
};

int main() {

std::cout << 'n';

NoLock noLock;
StrategizedLocking<NoLock> stratLock1{noLock};

{
ExclusiveLock exLock;
StrategizedLocking<ExclusiveLock> stratLock2{exLock};
{
SharedLock sharLock;
StrategizedLocking<SharedLock> startLock3{sharLock};
}
}

std::cout << 'n';

}



BasicLockable (1)’de bir nesnenin lo T veri türü üye işlevlerdir lock VE unlock desteklemek gerekir. Konsepti kullanmak kolaydır. Yerine typename kavramını kullanıyorum BasicLockable beyanname şeklinde StrategizedLocking (2).

Sıradaki ne?


Aralık tabanlı bir for döngüsünde kullanıcı tanımlı bir veri türü kullanmak için yineleyici protokolünü uygulaması gerekir. Bir sonraki makalemde iteratör protokolü hakkında daha fazla ayrıntıya gireceğim.


(rm)



Haberin Sonu
 
Üst