Щоб ваш код був вільно поєднаний, тут слід запам'ятати кілька простих речей:
Частина 1:
Технічно відомий як "Розмежування концерну". Кожен клас має певну роль, він повинен обробляти бізнес-логіку або логіку додатків. Постарайтеся уникати класу, який поєднує обидва обов'язки. тобто клас, що управляє (широкомасштабними) даними, є логікою програми, тоді як клас, який використовує дані, є бізнес-логікою.
Особисто я позначаю це (у своєму маленькому світі) як create it or use it
. Клас повинен створити об’єкт або використовувати об'єкт, який ніколи не повинен робити обом.
Частина 2:
Як здійснити розмежування проблеми.
В якості вихідної точки є дві прості методики:
Примітка. Шаблони дизайну не є абсолютними.
Вони повинні бути адаптовані до ситуації, але мають основну тему, схожу з усіма програмами. Тому не дивіться на приклади нижче та кажіть, що я повинен дотримуватися цього жорстко; це лише приклади (і злегка придумані для цього).
Ін'єкційна залежність :
Тут ви передаєте об’єкт, який використовує клас. Об'єкт, який ви передаєте, базується на інтерфейсі, щоб ваш клас знав, що з ним робити, але не потрібно знати фактичну реалізацію.
class Tokenizer
{
public:
Tokenizer(std::istream& s)
: stream(s)
{}
std::string nextToken() { std::string token; stream >> token;return token;}
private:
std::istream& stream;
};
Тут ми вводимо потік в токенізатор. Токенізатор не знає, який тип потоку, поки він реалізує інтерфейс std :: istream.
Шаблон локатора обслуговування :
Схема обслуговування локатора - незначна зміна залежно від ін'єкції залежності. Замість того, щоб дати об'єкту, який він може використовувати, ви передаєте йому об'єкт, який знає, як знайти (створити) об'єкт, який ви хочете використовувати.
class Application
{
public:
Application(Persister& p)
: persistor(p)
{}
void save()
{
std::auto_ptr<SaveDialog> saveDialog = persistor.getSaveDialog();
saveDialog.DoSaveAction();
}
void load()
{
std::auto_ptr<LoadDialog> loadDialog = persistor.getLoadDialog();
loadDialog.DoLoadAction();
}
private:
Persister& persistor;
};
Тут ми передаємо об’єкт програми об'єкт персистора. Під час виконання операції збереження / завантаження він використовує персистор для створення об'єкта, який насправді знає, як зробити дію. Примітка. Знову персистор - це інтерфейс, і ви можете надавати різні реалізації залежно від ситуації.
Це корисно, коли потрібен potentially
унікальний об'єкт щоразу, коли ви створюєте екземпляр дії.
Особисто мені здається, що це особливо корисно при написанні одиничних тестів.
Примітка шаблонів:
Шаблони дизайну є величезною темою для себе. Це аж ніяк не ексклюзивний перелік моделей, якими ви можете скористатися, щоб допомогти з нещільною зв'язкою; це лише загальна відправна точка.
З досвідом ви зрозумієте, що ви вже використовуєте ці зразки, тільки що ви не використовували їх офіційні назви. Стандартизуючи їхні імена (і змусивши всіх їх дізнатися), ми виявляємо, що ідеї легко і швидше передавати.