Tôi rất ủng hộ chiến lược được nêu trong câu trả lời của @DocBrown .
Tôi sẽ đề nghị một cải tiến cho câu trả lời.
Các cuộc gọi
myMap.Add(1,new Strategy1());
myMap.Add(2,new Strategy2());
myMap.Add(3,new Strategy3());
có thể được phân phối. Bạn không cần phải quay lại cùng một tệp để thêm một chiến lược khác, tuân thủ nguyên tắc Mở-Đóng thậm chí còn tốt hơn.
Giả sử bạn thực hiện Strategy1
trong tệp Strateg1.cpp. Bạn có thể có khối mã sau đây.
namespace Strategy1_Impl
{
struct Initializer
{
Initializer()
{
getMap().Add(1, new Strategy1());
}
};
}
using namespace Strategy1_Impl;
static Initializer initializer;
Bạn có thể lặp lại cùng một mã trong mọi tệp StargetyN.cpp. Như bạn có thể thấy, đó sẽ là rất nhiều mã lặp đi lặp lại. Để giảm trùng lặp mã, bạn có thể sử dụng một mẫu có thể được đặt trong một tệp có thể truy cập được cho tất cả các Strategy
lớp.
namespace StrategyHelper
{
template <int N, typename StrategyType> struct Initializer
{
Initializer()
{
getMap().Add(N, new StrategyType());
}
};
}
Sau đó, điều duy nhất bạn phải sử dụng trong Strateg1.cpp là:
static StrategyHelper::Initializer<1, Strategy1> initializer;
Dòng tương ứng trong StrategN.cpp là:
static StrategyHelper::Initializer<N, StrategyN> initializer;
Bạn có thể đưa việc sử dụng các mẫu lên một cấp độ khác bằng cách sử dụng một mẫu lớp cho các lớp Chiến lược cụ thể.
class Strategy { ... };
template <int N> class ConcreteStrategy;
Và sau đó, thay vì Strategy1
, sử dụng ConcreteStrategy<1>
.
template <> class ConcreteStrategy<1> : public Strategy { ... };
Thay đổi lớp người trợ giúp để đăng ký Strategy
s thành:
namespace StrategyHelper
{
template <int N> struct Initializer
{
Initializer()
{
getMap().Add(N, new ConcreteStrategy<N>());
}
};
}
Thay đổi mã trong Strateg1.cpp thành:
static StrategyHelper::Initializer<1> initializer;
Thay đổi mã trong StrategN.cpp thành:
static StrategyHelper::Initializer<N> initializer;