Strategy Kalıbı
Coddy'nin C++ Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 95 / 104.
Strategy kalıbı, bir algoritma ailesi tanımlar, her birini kapsüller ve bunların birbirleriyle değiştirilebilir olmasını sağlar. Bu, kodunu değiştirmeden bir nesnenin davranışını çalışma zamanında değiştirmenize olanak tanır; algoritma, onu kullanan istemcilerden bağımsız olarak değişir.
Örüntü üç bölümden oluşur: algoritma yöntemini bildiren bir Strateji arayüzü, farklı varyasyonları uygulayan Somut Stratejiler ve bir strateji kullanan bir Bağlam:
#include <iostream>
#include <memory>
// Strateji arayüzü
class PaymentStrategy {
public:
virtual void pay(int amount) = 0;
virtual ~PaymentStrategy() = default;
};
// Somut stratejiler
class CreditCardPayment : public PaymentStrategy {
public:
void pay(int amount) override {
std::cout << "Paid " << amount << " via Credit Card\n";
}
};
class PayPalPayment : public PaymentStrategy {
public:
void pay(int amount) override {
std::cout << "Paid " << amount << " via PayPal\n";
}
};
// Bağlam
class ShoppingCart {
std::unique_ptr<PaymentStrategy> strategy;
public:
void setPaymentMethod(std::unique_ptr<PaymentStrategy> s) {
strategy = std::move(s);
}
void checkout(int total) {
if (strategy) strategy->pay(total);
}
};
int main() {
ShoppingCart cart;
cart.setPaymentMethod(std::make_unique<CreditCardPayment>());
cart.checkout(100);
cart.setPaymentMethod(std::make_unique<PayPalPayment>());
cart.checkout(50);
}ShoppingCart hangi ödeme yöntemini kullandığını bilmez - yalnızca ayarlanmış olan strateji üzerinde pay() çağrısı yapar. setPaymentMethod() ile stratejileri çalışma zamanında değiştirebilir, böylece sistemi esnek hâle getirip yeni ödeme seçenekleriyle genişletmeyi kolaylaştırabilirsin.
Belirli bir görev için birden fazla algoritmanız olduğunda ve bunlar arasında dinamik olarak geçiş yapmak istediğinizde ya da davranışı seçmek için koşullu ifadelerden kaçınmak istediğinizde Strategy kullanın.
Görev
KolayFarklı gönderim yöntemlerine göre teslimat maliyetlerini hesaplamak için Strategy desenini kullanan bir Gönderim Hesaplayıcısı oluşturalım. Bu, algoritmaları çalışma zamanında değiştirmeniz gereken pratik bir senaryodur: aynı paket kara, hava veya ekspres yoluyla gönderilebilir ve her yöntemin kendine özgü fiyatlandırma mantığı vardır.
Kodunuzu üç dosyaya ayıracaksınız:
ShippingStrategy.h: Strateji arayüzünüzü ve somut gönderim stratejilerini tanımlayın.Saf sanal bir
ShippingStrategymetoduna sahip, gönderim maliyetini double olarak döndüren ve sanal bir yıkıcı içeren soyut bircalculateCost(double weight)sınıfı oluşturun.Ardından üç somut strateji uygulayın:
GroundShipping: ağırlık birimi başına1.5maliyet (weight * 1.5)AirShipping: ağırlık birimi başına4.0maliyet (weight * 4.0)ExpressShipping: ağırlık birimi başına6.5maliyet ve ayrıca sabit10.0ücret (weight * 6.5 + 10.0)
ShippingService.h: Bir gönderim stratejisi kullanan bağlam sınıfını oluşturun.ShippingServicesınıfınız, özel bir üye olarakstd::unique_ptr<ShippingStrategy>tutmalıdır. Şunları uygulayın:- Gönderim yöntemini değiştirmek için bir
setStrategy(std::unique_ptr<ShippingStrategy> strategy)metodu - Geçerli stratejiyi kullanarak maliyeti hesaplayıp döndüren bir
calculateShipping(double weight)metodu
calculateShippingçağrıldığında hiçbir strateji ayarlanmamışsa0.0döndürün.- Gönderim yöntemini değiştirmek için bir
main.cpp: Stratejilerin çalışma zamanında değiştirilmesini gösterin.İki girdi okuyun:
- Paket ağırlığı (double)
- Gönderim yöntemi:
ground,airveyaexpress
Bir
ShippingServiceoluşturun ve giriş yöntemine göre uygun stratejiyi ayarlayın. Gönderim maliyetini hesaplayıp yazdırın.Ardından farklı bir stratejiye geçin (girdi
airdeğilseair, aksi takdirdegroundkullanın) ve aynı ağırlık için maliyeti tekrar hesaplayın. Bu, stratejileri çalışma zamanında değiştirmenin gücünü gösterir.Her maliyeti kendi satırında, tam olarak bir ondalık basamakla ve yöntem adı önde olacak şekilde yazdırın:
[Method]: $[cost]
Örneğin, 5.0 ve ground girdileriyle:
Ground: $7.5
Air: $20.03.0 ve express girdileriyle:
Express: $29.5
Air: $12.010.0 ve air girdileriyle:
Air: $40.0
Ground: $15.0ShippingService sınıfının her fiyatlandırma algoritmasının ayrıntılarını bilmesinin gerekmediğine dikkat edin. Yalnızca o anda ayarlanmış olan stratejiye yetki verir. Hizmet sınıfını hiç değiştirmeden yeni gönderim yöntemlerini (drone teslimatı veya aynı gün teslimat gibi) kolayca ekleyebilirsiniz.
Kendin dene
#include <iostream>
#include <string>
#include <iomanip>
#include <memory>
#include "ShippingStrategy.h"
#include "ShippingService.h"
int main() {
double weight;
std::string method;
std::cin >> weight;
std::cin >> method;
// Çıktıyı 1 ondalık basamağa ayarla
std::cout << std::fixed << std::setprecision(1);
ShippingService service;
// TODO: Giriş yöntemine göre ("ground", "air" veya "express"):
// 1. Servis üzerinde uygun stratejiyi ayarla
// 2. Maliyeti hesapla ve şu formatta yazdır: "[Method]: $[cost]"
// TODO: Farklı bir stratejiye geç:
// - Giriş "air" ise, GroundShipping'e geç
// - Aksi takdirde, AirShipping'e geç
// Yeni maliyeti hesapla ve yazdır
return 0;
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Nesne Yönelimli Programlama bölümündeki tüm dersler
1OOP Temelleri
Harici DosyalarC++ Build ve DerlemeBaşlık Dosyaları ve Kaynak DosyalarıAd Alanları ve KapsamC++'ta OOP'ye GirişSınıflar ve Nesneler'this' İşaretçisiMetotlar (Üye Fonksiyonlar)Öznitelikler (Veri Üyeleri)Ctor ve Dtor TemelleriÖzet - Basit Hesap Makinesi4Sınıf Özellikleri
Örnek ve Statik ÜyelerGetter ve Setter MetotlarıConst Üye FonksiyonlarMutable Anahtar KelimesiStatik Metotlar ve DeğişkenlerFriend Fonksiyonlar ve SınıflarÖzet - Banka Hesabı Yöneticisi7Kalıtım
Temel KalıtımKalıtım Erişim SeviyeleriCtor ve Dtor Çağrılma SırasıMetot Geçersiz KılmaSanal Fonksiyonlar ve VTableÇoklu KalıtımSanal KalıtımÖzet - Çalışan Hiyerarşisi10STL Genel Bakış
STL Genel Bakış ve FelsefesiSTL KonteynerleriİteratörlerSTL AlgoritmalarıFunctor'lar ve Lambda İfadeleriÖzet - Kelime Frekansı13Tasarım Kalıpları 1. Bölüm
Tasarım Kalıplarına GirişSingleton KalıbıFactory ve Abstract FactoryBuilder KalıbıObserver KalıbıStrategy Kalıbı2Bellek Yönetimi
Stack ve Heap Bellekİşaretçiler ve ReferanslarDinamik Bellek (new/delete)C++'ta Akıllı İşaretçilerC++'ta RAIIÖzet - Dinamik Dizi Yöneticisi5Kapsülleme
C++'da Erişim BelirleyicilerDerinlemesine Erişim BelirleyicilerBilgi GizlemeStruct vs Classİç İçe ve Dahili SınıflarÖzet - Öğrenci Kayıt Sistemi8Çok Biçimlilik
Derleme ve Çalışma Zamanı Çok BiçimliliğiFonksiyon Aşırı YüklemeSanal Fonksiyonlara Yeniden BakışSaf Sanal FonksiyonlarSoyut SınıflarC++'ta Arayüz TasarımıDynamic Casting ve RTTIÖzet - Şekil Hesaplayıcı3Yapıcılar ve Yıkıcılar
Varsayılan YapıcıParametreli YapıcıKopya YapıcıTaşıma YapıcısıYapıcı İlklendirme ListeleriTemsilci YapıcılarYıkıcılara Derinlemesine BakışÜç / Beş / Sıfır KuralıÖzet - String Sınıfı6Operatör Aşırı Yükleme
Operatör Aşırı Yüklemeye GirişAritmetik Operatör Aşırı YüklemeKarşılaştırma Operatörü Aşırı YüklemeStream OperatörleriAtama Operatörü Aşırı Yükleme[] ve () Operatör Aşırı YüklemeTip Dönüşüm OperatörleriÖzet - Matris Sınıfı9Şablonlar
Fonksiyon ŞablonlarıSınıf ŞablonlarıŞablon ÖzelleştirmeVariadic ŞablonlarSFINAE ve Type Traits TemelleriÖzet - Generic KonteynerKendi başına pratik yap: Online C++ derleyicisi