2 -Open-Closed Principle :
اصل بعدی اشاره داره به این موضوع که کدی نوشته شده به گونه ی باشه که نسبت به توسعه باز باشه ولی نسبت به تغیرات بسته باشه این یعنی چی؟ به مثال زیر توجه کنید در این مثال ما قصد داریم یک سری محصولات را براساس رنگشون فیلتر کنیم.
enum class Color { Red, Green, Blue };
enum class Size { Small, Medium, Large };
struct Product
{
string name;
Color color;
Size size;
};
struct ProductFilter
{
typedef vector<Product*> Items;
};
ProductFilter::Items ProductFilter::by_color(Items items,Color color)
{
Items result;
for (auto& i : items)
if (i->color == color)
result.push_back(i);
return result;
}
فرض کنید مجددا از شما خواسته میشه که فیلتر اندازه را هم به کدتان اضافه کنید.
ProductFilter::Items ProductFilter::by_size(Items items,Size size)
{
Items result;
for (auto& i : items)
if (i->size == size)
result.push_back(i);
return result;
}
فرض مجدداً از شما درخواست میشه که هم نسبت به رنگ و اندازه با هم فیلتر کنید.
ProductFilter::Items ProductFilter::by_color_and_size(Items items, Size size, Color color)
{
Items result;
for (auto& i : items)
if (i->size == size && i->color == color)
result.push_back(i);
return result;
}
اگر دقت کنید OCP اینجا نقض شده در صورتیکه ما قصد داریم هر بار فیلتر جدید اضافه کنیم در صورتیکه داریم کل یونیت مربوط به فیلتر را تغییر میدم ساختار کد با در این مرحله به گونه ای تغییر کنه که اضافه کردن فیلتر جدید باعث توسعه کد بشه و هیچ جای دیگر کد جز خودش تغییر نکنه . به کد تغییر یافته در زیز دقت کنید:
//Test.h
#pragma once
#include <string>
#include <vector>
#include <iostream>
using namespace std;
enum class Color { Red, Green, Blue };
enum class Size { Small, Medium, Large };
struct Product
{
std::string name_;
Color color_;
Size size_;
};
using ProductP = Product *;
using ProductPVec = std::vector<ProductP>;
template<typename T>
struct AndSpec;
template<typename T>
struct Spec
{
virtual bool is_satisfy(T* value) = 0;
AndSpec<T> operator&&(T& value)
{
return AndSpec<T>(*this, value);
}
};
struct ColorSpec : public Spec<Product>
{
Color color_;
ColorSpec(Color color) :
color_(color) {}
bool is_satisfy(Product* value) override
{
return value->color_ == color_;
}
};
struct SizeSpec : public Spec<Product>
{
Size size_;
SizeSpec(Size size) :
size_(size) {}
bool is_satisfy(Product* value) override
{
return value->size_ == size_;
}
};
template <typename T>
struct AndSpec : Spec<T>
{
Spec<T>& first_;
Spec<T>& second_;
AndSpec(Spec<T>& first, Spec<T>& second) :
first_(first),
second_(second)
{
}
bool is_satisfy(T* value) override
{
return first_.is_satisfy(value) && second_.is_satisfy(value);
}
};
template<typename T>
struct Filter
{
ProductPVec filter(ProductPVec items,Spec<T>& spec)
{
ProductPVec result;
for (auto& item : items)
if (spec.is_satisfy(item))
result.push_back(item);
return result;
}
};
void print(Product* value);
void printAll(ProductPVec items);
//Test.cpp
#include "Test.h"
void print(Product* value)
{
cout << "name:" << value->name_ << endl;
}
void printAll(ProductPVec items)
{
for (auto& item : items)
print(item);
}
//main.cpp
#include "Test.h"
int main()
{
Product apple{ "Apple", Color::Green, Size::Small };
Product tree{ "Tree", Color::Green, Size::Large };
Product house{ "House", Color::Blue, Size::Large };
ProductPVec all{ &apple,&tree,&house };
auto green = ColorSpec(Color::Green);
auto large = SizeSpec(Size::Large);
auto spc = AndSpec<Product>(green,large);
Filter<Product> fp;
auto filtered = fp.filter(all, spc);
printAll(filtered);
}