Design patterns part 1

47
Шаблони проектування Частина 1

Transcript of Design patterns part 1

Page 1: Design patterns part 1

Шаблони проектування

Частина 1

Page 2: Design patterns part 1

Coupling and cohesion

Page 3: Design patterns part 1

Coupling (зв’язність)• Afferent– Скільки компонентів залежать від

модуля– Показує наскільки модуль

відповідальний

• Efferent– Від скількох компонентів залежить

модуль– Показує наскільки модуль

незалежний– Включає: наслідування, interface impl,

типи параметрів, типи змінних, exceptions,...

• Ca and Ce є метриками стабільності

Page 4: Design patterns part 1

Instability

I = Ce / (Ce + Ca)

• показує нестійкість до змін• 0 – стабільний модуль• 1 – нестабільний

Ми залежимо від

Залежать від нас

Page 5: Design patterns part 1

Cohesion (пов’язаність, зчеплення)

• Показує наскільки сильні взаємозв’язки між частинами одного модулю

• Чи всі методи класу використовують всі його поля

• Низька пов’язаність:– Клас з багатьма статичними

методами– “Несфокусований” клас

Page 6: Design patterns part 1

Програмне забезпечення

• Успішне– Legacy (унаслідуване, застаріле)–Maintainable (легко підтримуване)

• Неуспішне

Page 7: Design patterns part 1

Legacy software

• Довго експлуатується• Продовжує експлуатуватись• Задовільняє потреби замовника• Але разом з тим–Містить дефекти, не містить нових

функцій

• Важко покращується

Page 8: Design patterns part 1

Maintainable software

• Довго експлуатується• Продовжує експлуатуватись• Задовільняє потреби замовника• Але разом з тим–Містить дефекти, не містить нових

функцій

• Легко покращується

Page 9: Design patterns part 1

Бажані властивості

• Хочемо змінювати програму– Проясняються старі/з’являються нові

вимоги

• Не хочемо змінювати готові класи– Зміна – внесення нестабільності– Потрібно перетестувати– Залежності транзитивні

Page 10: Design patterns part 1

Low coupling + high cohesion сприяють легкому внесенню змін у

ПЗ

Більшість шаблонів проектування є рецептами для зниження coupling

та підвищення cohesion

Page 12: Design patterns part 1

Створення об’єктів, creational patterns

Page 13: Design patterns part 1

Dependencies

Page 14: Design patterns part 1

public class Survey { public SurveyState State { get; set; } public DateTime StartDate { get; set; } public DateTime FinishDate { get; set; }

public void Start() { State = SurveyState.InProgress; try { var email = new SmtpEmailSender(); email.Send("Survey has started!", Constants.AdminEmail); } catch (SmtpException e) { ... } }}

Page 15: Design patterns part 1

Survey

SmtpEmailSender

High level

module

Low level

module

Depends on

Page 16: Design patterns part 1

public class Survey { private readonly IEmailSender _email; public SurveyState State { get; set; } public DateTime StartDate { get; set; } public DateTime FinishDate { get; set; }

public Survey(IEmailSender email) { _email = email; }

public void Start() { State = SurveyState.InProgress; try { _email.Send("Survey has started!", Constants.AdminEmail); } catch (SmtpException e) { ... } }}

Page 17: Design patterns part 1

Survey

SmtpEmailSender

High level

module

IEmailSender

Implements

Page 18: Design patterns part 1

Survey

SmtpEmailSender

IEmailSender

Application

Page 19: Design patterns part 1

Survey

SmtpEmailSender

High level

module

IEmailSender

Dependency is inverted

Page 20: Design patterns part 1

Dependency inversion

• High level modules should not depend on low-level modules

• Both should depend on abstractions• Abstractions should not depend on

details• Details should depend on

abstractions

Page 21: Design patterns part 1

Що отримуємо• Залежності вказуються явно, немає

прихованих залежностей• Класи самодокументовані• Класи більше не відповідають за створення

об’єктів• Після створення клас гарантовано

знаходиться у робочому стані• Легко знаходити класи з багатьма

параметрами в конструкторі (і зменшувати їх відповідальності)

• Легше знаходити методи, яким потрібні не всі залежності класу

Page 22: Design patterns part 1

Приклад

public void Import(){ var importContext = _contextCreator.Create(_userName); // ... _fileImporter.Import(); // ...}

Page 23: Design patterns part 1

Прикладpublic void Import(){ var importContext = _contextCreator.Create(_userName); using (IFileImporter fileImporter = new FileImporter(importContext)) { fileImporter.Import(); }}

Page 24: Design patterns part 1

Abstract Factory

Page 25: Design patterns part 1

Потреба

• Залежність залежить від параметра, який не відомий клієнту на час його створення

• if/else та switch блоки для вирішення, яку залежність створити

• Залежність потрібно до-ініціалізувати

• Об’єкт повинен керувати часом життя залежності

Page 26: Design patterns part 1

SurveyImporter

FileImporter

Page 27: Design patterns part 1

SurveyImporter

FileImporter

IFileImporterFactory

IFileImporter

FileImporterFactory

Page 28: Design patterns part 1

Реалізація

• Виклик конструктора об’єкта+ передача параметра+ передача створених/отриманих залежностей

• switch, Dictionary<TParameter, Func<TResult>>

Page 29: Design patterns part 1

Часто фабрика повертає Null Object в default-вітці switch’а

public sealed class FileImporterFactory : IFileImporterFactory{ public IFileImporter Create(Context importContext) { switch (GetFileStorageType(importContext)) { case "csv": return new FileImporter(importContext, csvReader); case "xls": return new FileImporter(importContext, xlsReader); default: return new NullFileImporter(importContext); } }

Page 30: Design patterns part 1

Null Object

Page 31: Design patterns part 1

public SurveysImporter( IFileImporter headersFileImporter, IFileImporter dataFileImporter, IFileImporter additionalDataImporter){ if (headersFileImporter == null) { throw new ArgumentNullException("headersFileImporter"); } if (dataFileImporter == null) { throw new ArgumentNullException("dataFileImporter"); }

_headersFileImporter = headersFileImporter; _dataFileImporter = dataFileImporter; _additionalDataImporter = additionalDataImporter;}

Тут треба пояснюючий

коментар

Page 32: Design patterns part 1

public void Import(){ _headersFileImporter.Import(); // ... _dataFileImporter.Import(); // ... if (_additionalDataImporter != null) { _additionalDataImporter.Import(); }}

Буде розмножуват

ись по вашому коду

Page 33: Design patterns part 1

Потреба

• Код для NULL-випадку повинен бути ідентичним до решти випадків

Page 34: Design patterns part 1

Реалізаціяpublic sealed class NullFileImporter : IFileImporter{ public void Import() { }}

public sealed class SurveysImporter{ public void Import() { _headersFileImporter.Import(); // ... _dataFileImporter.Import(); // ... _additionalDataImporter.Import();}

Page 35: Design patterns part 1

Переваги

• Чистіший та стисліший код• Відсутність перевірок на null • Простіший код• Зменшення кількості

відповідальностей класів-клієнтів

Page 36: Design patterns part 1

Builder

Page 37: Design patterns part 1

Fluent Buildervar team = new Team( "Manchester United", "The Red Devils", Color.Red, "Manchester", "Old Trafford");

var builder = new TeamBuilder();var team = builder .CreateTeam("Real Madrid") .WithNickName("Los Merengues") .WithShirtColor(Color.White) .FromTown("Madrid") .PlayingAt("Santiago Bernabeu") .Build();

Page 38: Design patterns part 1

Призначення

• Конструювання складного об’єкта• Відділення логіки конструювання

від представлення даних об’єкта

Page 39: Design patterns part 1

Fluent Builder: Mocksvar workerPlanMock = new Mock<IWorkerPlan>();workerPlanMock .Setup(workerPlan => workerPlan.GetCountOfItemsToProcess()) .Returns(2);var worker = new Worker(workerPlanMock.Object);...

Page 40: Design patterns part 1

StringBuilderStringBuilder builder = new StringBuilder();builder.Append("...");builder.AppendFormat("...{0}", "value") .AppendLine() .Append("...");string result = builder.ToString();

Page 41: Design patterns part 1

SqlConnectionStringBuildervar builder = new SqlConnectionStringBuilder { DataSource = "localhost", InitialCatalog = "MyDB", IntegratedSecurity = true, ConnectTimeout = 10 // seconds };string connectionString = builder.ConnectionString;

Page 42: Design patterns part 1

Lazy Instantiation

Page 43: Design patterns part 1

Потреба public void Import(){ var importContext = _contextCreator.Create(_userName); if (ShouldReadFromFileSystem(importContext)) { FileImporter.Import(); }}

Page 44: Design patterns part 1

Реалізація private IFileImporter _fileImporter;private readonly Func<IFileImporter> _fileImporterFactory;

private IFileImporter FileImporter{ get { if (_fileImporter == null) { _fileImporter = _fileImporterFactory(); } return _fileImporter; }}

Page 45: Design patterns part 1

Призначення

• Відкладення створення об’єкта до моменту, коли об’єкт стає необхідний

• Оптимізація • Thread safety!

Page 46: Design patterns part 1

Lazy<T>private readonly Lazy<IFileImporter> _fileImporter;

private IFileImporter FileImporter{ get { return _fileImporter.Value; }}

Page 47: Design patterns part 1

Створення об’єктів• Coupling & Cohesion• Dependencies, Dependency

Inversion• Abstract Factory• Null Object• Fluent Builder• Lazy Instantiation