design patterns part 2

Post on 30-Jun-2015

1.885 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

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

Частина 2

Розглянемо

• Presentation pattern Model View Presenter

• Шаблони поведінки• Структурні шаблони• Деякі вже відомі нам шаблони

Model View Presenter

Призначення

Розділення • Даних для показу• Логіки програми• Відображення даних

View Model

Presenter

updates

fetches

change

request

displays

Сповіщає Presenter про

дії користувача,відображає

дані

Завантажує дані, передає дані на View, реагує на дії

користувача

Дані для показу

View Model

PresenterUI

DomainData

Access

Відповідальності: Model

• Контейнер для даних для відображення• Supervising Controller: View знає про

Модель• Passive View: View не знає про Модель• Також може бути класом з предметної

області

Відповідальності: View

• Є формою, показує UI• Створює Презентер, передає себе йому• Перенаправляє дії користувача

Презентеру• Може знати про Модель• Або може надавати детальний

інтерфейс для встановлення даних• Звертається до конкретного

Презентера

Відповідальності: Presenter

• Реагує на дії користувача• Оновлює View даними з Моделі• Позбавляє View відповідальності за

логіку та взаємодію з бізнес-класами та data access– Презентер отримує дані з бізнес-рівня– Трансформація/фільтрування даних– Презентер зберігає зміни, зроблені

користувачем

• Звертається до View через інтерфейс IView

Модифікації

• Supervising Controller– View відповідає за data binding Моделі– Презентер передає Модель на View– Презентер керує складнішими

взаємодіями

• Passive View– Презентер відповідає за передачу

кожної частини даних на View– View лише відображає передані

прості дані

Застосовується

• Windows Forms– Існують розвинені MVP фреймворки

• ASP.NET Web Forms

Strategy

public sealed class SurveysImporter { public void Import() { // ... initialize import here switch (GetFileStorageType(importContext)) { case SurveysStorageType.Xls: ImportFromExcel(); break; case SurveysStorageType.Csv: ImportFromCsvFile(); break; case ... default: DoNothingButLog(); break; } // ... report import completed successfully }

public sealed class SurveysImporterWithStrategy{ private readonly IFileImporterStrategy fileImporterStrategy; public void Import() { // ... initialize import here fileImporterStrategy.Import(); // ... report import completed successfully }

Призначення

• Інкапсуляція алгоритму• Зміна та розвиток алгоритму

окремо від клієнта• Винесення наборів різної

поведінки з класу• Усунення умовних операторів• Уникнення зміни класу при

додаванні нового алгоритму

Реалізація

• Створення класу-стратегії для кожної варіації алгоритму

• Створення спільного інтерфейсу для всіх цих алгоритмів

• Стратегія може використовувати клас-клієнт

• Або інший контекст

public class FilesSender{ public void SendToServer(Directory directory, Context context) { if (context.SendTopLevelFilesFirst) { foreach (var file in directory.Files) { SendToServer(file); } foreach (var childDirectory in directory.Directories) { SendToServer(childDirectory, context); } }

Higher order functions

• Є стратегіями

public class FilesSender{ private readonly Func<Directory, IEnumerable<File>> enumerateFiles;

public FilesSenderWithStrategy( Func<Directory, IEnumerable<File>> directoryTraverser) { enumerateFiles = directoryTraverser; }

public void SendToServer(Directory directory, Context context) {

foreach (var file in enumerateFiles(directory)) { SendToServer(file); } }

Template Method

public class SurveysImporter{ public void Import() { InitializeImport(); DoImport(); NotifyUsers(); ReportSuccessfullCompletion(); }

public class CsvSurveysImporter : SurveysImporterWithTemplateMethod{ protected override void DoImport() { // CSV import implementation here }

protected override void NotifyUsers() { // users notification implementation here }}

Призначення• Алгоритм складається з декількох

кроків• Реалізація одного кроку може

змінюватись• (або декількох кроків)• Інкапсуляція незмінної послідовності

кроків• Можливість задати реалізацію кроків,

що можуть змінюватись• Зміна кроків алгоритму без зміни його

структури

Реалізація

• Підкласи перевизначають окремі кроки алгоритму, визначеного в базовому класі

• Базується на наслідуванні• Альтернатива – Strategy

Приклад

• ASP.NET page lifecycle– OnInit(), OnLoad() etc.

Command

private void Import(Survey survey){    if (survey.CreatedBy == currentUser &&         survey.CreatedOn < DateTime.Today &&         (            new[] { SurveyState.New, SurveyState.Finished }                .Contains(survey.State) ||            survey.State == SurveyState.Paused &&  !survey.HasAnswers        ) &&        !AlreadyExistsSurveyWithTitle(survey.Title))    {        // create new or update existing survey    }}

Призначення

• Представлення дії як об’єкта• Відділення виконання дії від

деталей і залежностей, необхідних для реалізації дії

• Додавання нових дій без зміни клієнтів

public interface ICommand{ void Execute();} Не приймає

аргументів

public interface ICommand<T>{ void ExecuteFor(T obj);}

public class ImportSurveyCommand : ICommand<Survey>{    private readonly string currentUser;    private readonly object importContext;

    public ImportSurveyCommand(string currentUser,         object importContext)    {        this.currentUser = currentUser;        this.importContext = importContext;    }

    public void ExecuteFor(Survey obj)    {        // create new or update existing survey    }}

private void Import(Survey survey){ if (survey.CreatedBy == currentUser && ...) {     var importSurvey = new ImportSurveyCommand( currentUser,  GetImportContext());     importSurvey.ExecuteFor(survey); }}

public interface ICommand{    bool CanExecute();    void Execute();    void Undo();}

Команда може використовуватись для undo

функціональності

Specification

private void Import(Survey survey){    if (survey.CreatedBy == currentUser &&         survey.CreatedOn < DateTime.Today &&         (            new[] { SurveyState.New, SurveyState.Finished }                .Contains(survey.State) ||            survey.State == SurveyState.Paused &&  !survey.HasAnswers        ) &&        !AlreadyExistsSurveyWithTitle(survey.Title))    {        // create new or update existing survey    }}

Передумови

• Бізнес-правило містить багато коду• Правило логічно складне• Правило може часто змінюватись• Правил може бути декілька

• Призначення: спрощення коду класу-клієнта

public interface ISpecification<T>{    bool IsSatisfiedBy(T obj);}

public class SurveyShouldBeImported :  ISpecification<Survey>{    public bool IsSatisfiedBy(Survey obj)    {        // ...    }}

Реалізація

• Інкапсулює булеве бізнес-правило• Можливі композитні Специфікації– AndSpecification, OrSpecification,

NotSpecification

• Можливе поєднання Команд та Специфікацій

public class AndSpecification<T> : ISpecification<T>{    private readonly ISpecification<T> first;    private readonly ISpecification<T> second;

    public AndSpecification(ISpecification<T> first,        ISpecification<T> second)    {        this.first = first;        this.second = second;    }

    public bool IsSatisfiedBy(T obj)    {        return first.IsSatisfiedBy(obj) &&             second.IsSatisfiedBy(obj);    }}

Adapter

Призначення

• Класи-клієнти використовують певний інтерфейс

• Потрібне перетворення інтерфейсу одного класу в інтерфейс іншого

• Для використання існуючих класів • Адаптує один інтерфейс до іншого

Прикладpublic interface ISurveyRepository{ IList<Survey> GetAll(); Survey Get(int id);}

Decorator

Призначення

• Зміна поведінки об’єкта без зміни інтерфейсу

• Додання функціональності динамічно

• Приклад: Додавання валідації

public interface ISurveysImporter{    void Import();}

public sealed class SurveysImporter :  ISurveysImporter{ ...    public void Import()    {        // ... initialize import here        fileImporterStrategy.Import();        // ... report completed successfully    }}

public sealed class SecurityCheckingSurveysImporter :  ISurveysImporter    {        private readonly ISurveysImporter importer;

        public void Import()        {            if (GetCurrentUserRole() != "Admin")            {                throw new InvalidOperationException( "User is not allowed to import surveys.");            }            importer.Import();        }...

Реалізація• Декоратор реалізує інтерфейс

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

початковий об’єкт• Початковий об’єкт не знає про

додаткову функціональність• Декоратори можуть поєднуватись• Композиція замість наслідування

Вже відомі шаблони• Iterator– IEnumerable<T> + IEnumerator<T>– yield return -- компілятор сам генерує

ітератор

• Observer– C# events, based on delegates

• Proxy– Доступ до веб-сервісів

• MVC• Repository

top related