Общие темы. Тема 02.

107
Темы лекции: SOLID. Паттерны проектирования Игорь Шкулипа, к.т.н.

Transcript of Общие темы. Тема 02.

Page 1: Общие темы. Тема 02.

Темы лекции: SOLID. Паттерны проектирования

Игорь Шкулипа, к.т.н.

Page 2: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 2

SOLID принципы

Page 3: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 3

SOLID. Принципы проектирования классов

SOLID – это акроним названий пяти основных принциповпроектирования классов, сформулированных Робертом Мартином:

•Single responsibility (принцип одной ответственности),

•Open for extension and closed for modification (принципоткрытости/закрытости, или открытость для расширения изакрытость для модификации),

•Liskov substitution (принцип подстановки Лисков),

•Interface segregation (принцип разделения интерфейса),

•Dependency inversion (принцип инверсии зависимостей).

Page 4: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 4

Single Responsibility

Принцип единственной ответственности (Single Responsibility Principle)часто определяют так: у объекта должна быть только одна причина дляизменения; чем больше файл или класс, тем труднее достичь этойцели.

Этот принцип говорит о том, что по-хорошему каждый класс долженрешать только одну задачу. Это совсем не значит, что в класседолжен быть всего один метод. Это означает, что методы классадолжны быть связаны одной общей целью.

Page 5: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 5

Single Responsibility

class Persone {

public string Name { get; set; }

public string Surname { get; set; }

public string Middle { get; set; }

public void LoadFromDatabase() { }

public void SaveToDatabase() { }

public void PrintToPrinter() { }

}class Persone {

public string Name { get; set; }

public string Surname { get; set; }

public string Middle { get; set; }

}

class PersoneDatabase {

public Persone LoadFromDatabase() { }

public void SaveToDatabase(Persone p) { }

}

class PersonePrinter {

public void PrintToPrinter(Persone p) { }

}

Page 6: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 6

Open for Extension and Closed for Modification

Объекты проектирования (классы, функции, модули и т.д.) должны бытьоткрыты для расширения, но закрыты для модификации.

Этот принцип говорит о том, что классы нужно проектировать так, чтобывпоследствии иметь возможность изменять поведение класса, неизменяя его код.

Page 7: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 7

Open for Extension and Closed for Modification

class PersonePrinter {

public void PrintToPrinter(Persone p) { }

}

class PersonePrinter {

public void PrintToPrinter(Persone p) { }

public void PrintToPrinterShortForm(Persone p) { }

public void PrintToPrinterDetailedForm(Persone p) { }

}

interface IPrintForm { List<string> Formats { get; set; } }

class PrintFormGeneral : IPrintForm {}

class PrintFormShort : IPrintForm { }

class PrintFormDetailed : IPrintForm { }

class PersonePrinter

{

public void PrintToPrinter(Persone p, IPrintForm f) { }

}

Page 8: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 8

Liskov Substitution

Функции, которые используют ссылки на базовые классы, должны иметьвозможность использовать объекты производных классов, не зная обэтом.

Page 9: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 9

Liskov Substitution

class PersonePrinter

{

public void PrintToPrinter(Persone p, IPrintForm f) {

//...

var shortForm = f as PrintFormShort;

if (shortForm != null) { ... }

//...

var detailedForm = f as PrintFormDetailed;

if (detailedForm != null) { ... }

//...

}

}

class PersonePrinter

{

public void PrintToPrinter(Persone p, IPrintForm f) {

//...

f.FormatReport(p);

//...

}

}

Page 10: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 10

Interface Segregation

Принцип изоляции/разделения интерфейса говорит о том, что клиент недолжен вынужденно зависеть от элементов интерфейса, которые он неиспользует.

Page 11: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 11

Interface Segregation

interface IEmployee {

void UseComputer();

void Develop();

void Test();

}

class SoftDeveloper : IEmployee {

public void UseComputer() { }

public void Develop() { }

public void Test() {/* How??? */}

}

class SoftTester : IEmployee {

public void UseComputer() { }

public void Develop() {/* How??? */}

public void Test() { }

}

interface IEmployee {

void UseComputer();

}

interface IDeveloper {

void Develop();

}

interface ITester {

void Test();

}

class SoftDeveloper : IEmployee, IDeveloper {

public void UseComputer() { }

public void Develop() { }

}

class SoftTester : IEmployee, ITester {

public void UseComputer() { }

public void Test() { }

}

Page 12: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 12

Dependency Inversion

•Модули верхних уровней не должны зависеть от модулей нижнихуровней.

•Оба типа модулей должны зависеть от абстракций.

•Абстракции не должны зависеть от деталей.

•Детали должны зависеть от абстракций.

Page 13: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 13

Dependency Inversion

class SoftDeveloper {

public void Develop() { }

}

class Manager

{

private readonly SoftDeveloper dev =

new SoftDeveloper();

public void Manage() {

dev.Develop();

}

}

interface IDeveloper {

void Develop();

}

class SoftDeveloper: IDeveloper {

public void Develop() { }

}

class Manager {

private IDeveloper dev;

public Manager(IDeveloper developer) {

dev = developer;

}

public void Manage() {

dev.Develop();

}

}

Page 14: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 14

Паттерны проектирования

Page 15: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 15

Паттерны (шаблоны проектирования)

Паттерн описывает задачу, которая снова и снова возникает в работе, а так жепринцип ее решения, причем таким образом, что это решение можно потомиспользовать много раз, ничего не изобретая заново.

В общем случае паттерн состоит из четырех основных элементов:

Имя. Присваивание паттернам имен позволяет проектировать на более высокомуровне абстракции. С помощью имен паттернов можно вести общение сколлегами. Назначение паттернам имен упрощает общение в профессиональнойсреде.

Задача - это описание того, когда следует применять паттерн. Необходимосформулировать задачу и ее контекст. Может описываться конкретная проблемапроектирования, например способ представления алгоритмов в виде объектов.Так же задача может включать перечень условий, при выполнении которых имеетсмысл применять данный паттерн.

Решение представляет собой описание элементов дизайна, отношений междуними, функций каждого элемента. Конкретный дизайн или реализация не имеютсяввиду, поскольку паттерн – это шаблон, применимый в самых разных ситуациях.

Результаты - это следствия применения паттерна и разного рода компромиссы.Хотя при описании проектных решений о последствиях часто не упоминают, знатьо них необходимо, чтобы можно было выбрать между различными вариантами иоценить преимущества и недостатки данного паттерна.

Page 16: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 16

Паттерны (шаблоны проектирования)

Паттерн описывает задачу, которая снова и снова возникает в работе, а так жепринцип ее решения, причем таким образом, что это решение можно потомиспользовать много раз, ничего не изобретая заново.

В общем случае паттерн состоит из четырех основных элементов:

Имя. Присваивание паттернам имен позволяет проектировать на более высокомуровне абстракции. С помощью имен паттернов можно вести общение сколлегами. Назначение паттернам имен упрощает общение в профессиональнойсреде.

Задача - это описание того, когда следует применять паттерн. Необходимосформулировать задачу и ее контекст. Может описываться конкретная проблемапроектирования, например способ представления алгоритмов в виде объектов.Так же задача может включать перечень условий, при выполнении которых имеетсмысл применять данный паттерн.

Решение представляет собой описание элементов дизайна, отношений междуними, функций каждого элемента. Конкретный дизайн или реализация не имеютсяввиду, поскольку паттерн – это шаблон, применимый в самых разных ситуациях.

Результаты - это следствия применения паттерна и разного рода компромиссы.Хотя при описании проектных решений о последствиях часто не упоминают, знатьо них необходимо, чтобы можно было выбрать между различными вариантами иоценить преимущества и недостатки данного паттерна.

Page 17: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 17

Классификация паттернов

Паттерны проектирования программных систем делятся наследующие категории:

Архитектурные паттерны. Описывают структурную схемупрограммной системы в целом. В данной схеме указываютсяотдельные функциональные составляющие системы,называемые подсистемами, а также взаимоотношения междуними.

Паттерны проектирования. описывают схемы детализациипрограммных подсистем и отношений между ними, при этом онине влияют на структуру программной системы в целом исохраняют независимость от реализации языкапрограммирования.

Идиомы - низкоуровневые паттерны, имеют дело с вопросамиреализации какой-либо проблемы с учетом особенностейданного языка программирования.

Page 18: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 18

Паттерны проектирования

Паттерны проектирования делятся на следующие категории:

Порождающие - шаблоны проектирования, которыеабстрагируют процесс создания объектов. Они позволяютсделать систему независимой от способа создания, композициии представления объектов.

Структурные - шаблоны проектирования, в которыхрассматривается вопрос о том, как из классов и объектовобразуются более крупные структуры.

Поведенческие - шаблоны проектирования, определяющиеалгоритмы и способы реализации взаимодействия различныхобъектов и классов.

Page 19: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 19

Порождающие паттерны

•Singleton (Одиночка) - контролирует создание единственногоэкземпляра некоторого класса и предоставляет доступ к нему.

•Factory Method (Фабричный метод) - В его классическом вариантевводится полиморфный класс Factory, в котором определяетсяинтерфейс фабричного метода, а ответственность за создание объектовконкретных классов переносится на производные от Factory классы, вкоторых этот метод переопределяется.

•Abstract Factory (Абстрактная фабрика) - использует несколькофабричных методов и предназначен для создания целого семейства илигруппы взаимосвязанных объектов.

•Builder (Строитель) - определяет процесс поэтапного конструированиясложного объекта, в результате которого могут получаться разныепредставления этого объекта.

•Prototype (Прототип) - создает новые объекты с помощью прототипов.Прототип - некоторый объект, умеющий создавать по запросу копиюсамого себя.

•Object Pool (Пул объектов) - используется в случае, когда созданиеобъекта требует больших затрат или может быть создано толькоограниченное количество объектов некоторого класса.

Page 20: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 20

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

public class Singleton

{

public static Singleton Instance

{

get

{

if (instance == null) instance = new Singleton();

return instance;

}

}

public void Method1() { Console.WriteLine("Singleton.Method1"); }

public void Method2() { Console.WriteLine("Singleton.Method2"); }

private Singleton() { }

private static Singleton instance;

}

class Program

{

static void Main(string[] args)

{

Singleton.Instance.Method1();

Singleton.Instance.Method2();

}

}

Page 21: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 21

Применение Singleton

Применяется, когда нужен только один экземпляр класса.Например для хранения глобальной конфигурации системы,для ведения логов, связи с базой данных и т.д.

Основное преимущество перед глобальными переменными втом, что экземпляр класса создается не при инициализациипрограммы, а по первому требованию.

Page 22: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 22

Factory Method

Паттерн Factory Method может быть полезным в решенииследующих задач:

1. Система должна оставаться расширяемой путем добавленияобъектов новых типов. Непосредственное использованиеоператора new является нежелательным, так как в этомслучае код создания объектов с указанием конкретных типовможет получиться разбросанным по всему приложению. Тогдатакие операции как добавление в систему объектов новыхтипов или замена объектов одного типа на другой будутзатруднительными. Паттерн Factory Method позволяет системеоставаться независимой как от самого процесса порожденияобъектов, так и от их типов.

2. Заранее известно, когда нужно создавать объект, нонеизвестен его тип.

Page 23: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 23

Описание паттерна Factory Method

Для того, чтобы система оставалась независимой от различных типовобъектов, паттерн Factory Method использует механизм полиморфизма -классы всех конечных типов наследуются от одного абстрактногобазового класса, предназначенного для полиморфного использования. Вэтом базовом классе определяется единый интерфейс, через которыйпользователь будет оперировать объектами конечных типов.

Для обеспечения относительно простого добавления в систему новых типовпаттерн Factory Method локализует создание объектов конкретных типов вспециальном классе-фабрике. Методы этого класса, посредством которыхсоздаются объекты конкретных классов, называются фабричными.

Существуют две разновидности паттерна Factory Method:

Обобщенный конструктор, когда в том же самом полиморфном базовомклассе, от которого наследуются производные классы всех создаваемых всистеме типов, определяется статический фабричный метод. В качествепараметра в этот метод должен передаваться идентификатор типасоздаваемого объекта.

Классический вариант фабричного метода, когда интерфейс фабричныхметодов объявляется в независимом классе-фабрике, а их реализацияопределяется конкретными подклассами этого класса.

Page 24: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 24

Классическая реализация Factory Method. Классы-результаты фабрики

public abstract class BaseClass

{

public abstract string GetName();

}

public class DerivedClass1 : BaseClass

{

public override string GetName()

{

return "Derived Class 1";

}

}

public class DerivedClass2 : BaseClass

{

public override string GetName()

{

return "Derived Class 2";

}

}

Page 25: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 25

Классическая реализация Factory Method. Классы фабрик

public abstract class Factory

{

public abstract BaseClass FactoryMethod();

}

class Factory1 : Factory

{

public override BaseClass FactoryMethod()

{

return new DerivedClass1();

}

}

class Factory2 : Factory

{

public override BaseClass FactoryMethod()

{

return new DerivedClass2();

}

}

Page 26: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 26

Классическая реализация Factory Method. Использование

class Program

{

static void Main(string[] args)

{

Factory1 fact1 = new Factory1();

Factory2 fact2 = new Factory2();

Factory[] factories = { fact1, fact2 };

for (int i = 0; i < factories.Length; i++)

{

BaseClass bc = factories[i].FactoryMethod();

Console.WriteLine(

"Type={0}, Object={1}",

bc.GetType().ToString(), bc.GetName());

}

Console.ReadKey();

}

} Type=HelloWorld.DerivedClass1, Object=Derived Class 1

Type=HelloWorld.DerivedClass2, Object=Derived Class 2

Page 27: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 27

Преимущества и недостатки

Преимущества паттерна Factory Method:

–Создает объекты разных типов, позволяя системе оставатьсянезависимой как от самого процесса создания, так и от типовсоздаваемых объектов.

Недостатки паттерна Factory Method:

–В случае классического варианта паттерна даже дляпорождения единственного объекта необходимо создаватьсоответствующую фабрику

Page 28: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 28

Abstract Factory

Паттерн Abstract Factory стоит использовать, когда:

–Система должна оставаться независимой как от процессасоздания новых объектов, так и от типов порождаемыхобъектов. Непосредственное использование оператора new вкоде приложения нежелательно.

–Необходимо создавать группы или семействавзаимосвязанных объектов, исключая возможностьодновременного использования объектов из разных семействв одном контексте.

Page 29: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 29

Классы для 1-й фабрики

public abstract class BaseClass1

{

public abstract string GetName();

}

public class DerivedClass11 : BaseClass1

{

public override string GetName()

{

return "Derived Class 11";

}

}

public class DerivedClass21 : BaseClass1

{

public override string GetName()

{

return "Derived Class 21";

}

}

Page 30: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 30

Классы для 2-й фабрики

public abstract class BaseClass2

{

public abstract string GetName();

}

public class DerivedClass12 : BaseClass2

{

public override string GetName()

{

return "Derived Class 12";

}

}

public class DerivedClass22 : BaseClass2

{

public override string GetName()

{

return "Derived Class 22";

}

}

Page 31: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 31

Классы фабрик

public abstract class AbstractFactory

{

public abstract BaseClass1 FactoryMethod1();

public abstract BaseClass2 FactoryMethod2();

}

class AbstractFactory1 : AbstractFactory {

public override BaseClass1 FactoryMethod1() {

return new DerivedClass11();

}

public override BaseClass2 FactoryMethod2() {

return new DerivedClass12();

}

}

class AbstractFactory2 : AbstractFactory {

public override BaseClass1 FactoryMethod1() {

return new DerivedClass21();

}

public override BaseClass2 FactoryMethod2() {

return new DerivedClass22();

}

}

Page 32: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 32

Использованиеclass Program

{

static void UseAbstractFactory(AbstractFactory af)

{

BaseClass1 bc1 = af.FactoryMethod1();

BaseClass2 bc2 = af.FactoryMethod2();

Console.WriteLine(bc1.GetName());

Console.WriteLine(bc2.GetName());

}

static void Main(string[] args)

{

AbstractFactory af1 = new AbstractFactory1();

AbstractFactory af2 = new AbstractFactory2();

UseAbstractFactory(af1);

UseAbstractFactory(af2);

Console.ReadKey();

}

}

Derived Class 11

Derived Class 12

Derived Class 21

Derived Class 22

Page 33: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 33

Паттерн «Прототип»

Использует для создания новых объектов копию самого себя.

Паттерн Prototype (прототип) можно использовать в следующихслучаях:

–Система должна оставаться независимой как от процессасоздания новых объектов, так и от типов порождаемыхобъектов. Непосредственное использование оператора new вкоде приложения считается нежелательным.

–Необходимо создавать объекты, точные классы которыхстановятся известными уже на стадии выполненияпрограммы.

Page 34: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 34

Интерфейс ICloneable

Поддерживает копирование, при котором создается новый экземпляркласса с тем же значением, что и у существующего экземпляра.

Метод Clone() создает новый объект, являющийся копией текущегоэкземпляра.

Метод MemberwiseClone для создания неполной копии создает новыйобъект, а затем копирует в него нестатические поля текущего объекта.Если поле относится к типу значения, выполняется побитовоекопирование полей. Если поле относится к ссылочному типу,копируются ссылки, а не объекты, на которые они указывают;следовательно, ссылки в исходном объекте и его клоне указывают наодин и тот же объект.

Page 35: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 35

Примерclass DeepStructure {

public int A { get; set; }

public int B { get; set; }

}

class CloneClass {

public int X { get; set; }

public int Y { get; set; }

public DeepStructure ds;

public CloneClass()

{

ds = new DeepStructure();

}

public override string ToString()

{

return

X.ToString() + " " +

Y.ToString() + " " +

ds.A.ToString() + " " +

ds.B.ToString() + " " +

ds.GetHashCode();

}

}

class ShallowCloneClass :

CloneClass, ICloneable

{

public object Clone()

{

return

(ShallowCloneClass)this.MemberwiseClone();

}

}

class DeepCloneClass :

CloneClass, ICloneable

{

public object Clone()

{

DeepCloneClass result =

new DeepCloneClass();

result.X = this.X;

result.Y = this.Y;

result.ds = new DeepStructure();

result.ds.A = this.ds.A;

result.ds.B = this.ds.B;

return result; ;

}

}

Page 36: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 36

Использование

3

6

class Program

{

static void Main(string[] args)

{

ShallowCloneClass sc1 = new ShallowCloneClass();

sc1.X = 1; sc1.Y = 2; sc1.ds.A = 3; sc1.ds.B = 4;

ShallowCloneClass sc2 = (ShallowCloneClass)sc1.Clone();

Console.WriteLine(sc1.ToString());

Console.WriteLine(sc2.ToString());

DeepCloneClass dc1 = new DeepCloneClass();

dc1.X = 1; dc1.Y = 2; dc1.ds.A = 3; dc1.ds.B = 4;

DeepCloneClass dc2 = (DeepCloneClass)dc1.Clone();

Console.WriteLine(dc1.ToString());

Console.WriteLine(dc2.ToString());

Console.ReadKey();

}

}

1 2 3 4 27226607

1 2 3 4 27226607

1 2 3 4 42549079

1 2 3 4 66790640

Page 37: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 37

Паттерн Builder

Паттерн Builder может помочь в решении следующих задач:

–В системе могут существовать сложные объекты, созданиекоторых за одну операцию затруднительно или невозможно.Требуется поэтапное построение объектов с контролемрезультатов выполнения каждого этапа.

–Данные должны иметь несколько представлений. Например,если есть некоторый исходный документ в формате RTF (RichText Format), в общем случае содержащий текст,графические изображения и служебную информацию оформатировании (размер и тип шрифтов, отступы и др.).Если этот документ в формате RTF преобразовать в другиеформаты (например, Microsoft Word или простой ASCII-текст),то полученные документы и будут представлениямиисходных данных.

Page 38: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 38

Описание паттерна Builder

Паттерн Builder отделяет алгоритм поэтапного конструированиясложного объекта от его внешнего представления так, что спомощью одного и того же алгоритма можно получать разныепредставления этого объекта.

Для этого паттерн Builder определяет алгоритм поэтапногосоздания продукта в специальном классе Director(распорядитель), а ответственность за координацию процессасборки отдельных частей продукта возлагает на иерархиюклассов Builder. В этой иерархии базовый класс Builderобъявляет интерфейс для построения отдельных частейпродукта, а соответствующие подклассы конкретныхстроителей их реализуют подходящим образом, например,создают или получают нужные ресурсы, сохраняютпромежуточные результаты, контролируют результатывыполнения операций.

Page 39: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 39

Реализация паттерна Builder. Класс Computer

class Computer

{

public string Name { get; set; }

public string CPU { get; set; }

public string RAM { get; set; }

public string HDD { get; set; }

public string VGA { get; set; }

public void Print()

{

Console.Write(

"{0}: {1}/{2}/{3}/{4}\n",

Name, CPU, RAM, HDD, VGA);

}

}

Page 40: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 40

Классы-строителиinterface ICompBuilder {

Computer Build();

}

class GameCompBuilder : ICompBuilder {

private Computer computer;

public GameCompBuilder() { computer = new Computer(); }

Computer ICompBuilder.Build() {

computer.Name = "Game Computer";

computer.CPU = "Core i7 3.0 GHz";

computer.RAM = "8 Gb";

computer.HDD = "1 Tb";

computer.VGA = "GeForce GTX 560";

return computer;

} }

class OfficeCompBuilder : ICompBuilder {

private Computer computer;

public OfficeCompBuilder() { computer = new Computer(); }

Computer ICompBuilder.Build() {

computer.Name = "Office Computer";

computer.CPU = "Core i3 3.0 GHz";

computer.RAM = "2 Gb";

computer.HDD = "500 Gb";

computer.VGA = "Intel GMA 4000";

return computer;

} }

Page 41: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 41

Класс-директор

class Director

{

private ICompBuilder builder;

public Director() { }

public void SetBuilder(ICompBuilder builder)

{

this.builder = builder;

}

public Computer GetComp()

{

return builder.Build();

}

}

Page 42: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 42

Использование строителей

class Program

{

static void Main(string[] args)

{

Director director = new Director();

//Building Game Computer

director.SetBuilder(new GameCompBuilder());

Computer comp = director.GetComp();

comp.Print();

//Building Office Computer

director.SetBuilder(new OfficeCompBuilder());

comp = director.GetComp();

comp.Print();

Console.ReadKey();

}

}Game Computer: Core i7 3.2 GHz/16 Gb/1 Tb/GeForce GTX 960

Office Computer: Core i3 3.0 GHz/2 Gb/500 Gb/Intel GMA 5000

Page 43: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 43

StringBuilder

Предоставляет изменяемую строку символов.

[SerializableAttribute]

[ComVisibleAttribute(true)]

public sealed class StringBuilder : ISerializable

Операция объединения объекта String всегда создает новый объект изсуществующей строки и новых данных. Объект StringBuilderподдерживает буфер для размещения и конкатенации новых данных.Новые данные добавляются в имеющийся буфер только в том случае,если в нем имеется достаточное свободное пространство для ихразмещения, в противном случае выделяется новый буфердостаточного размера, данные из оригинального буфера копируются вдругой буфер, и новые данные добавляются уже в новый буфер.

Page 44: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 44

Пример

class Program

{

static void Main(string[] args)

{

string strText1 = "Hello" + "," + " " + "World" + "!";

string strText2 = "";

StringBuilder strBuilder = new StringBuilder(strText2);

strBuilder.Append("Hello");

strBuilder.Append(",");

strBuilder.Append(" ");

strBuilder.Append("World");

strBuilder.Append("!");

strText2 = strBuilder.ToString();

Console.WriteLine(strText1);

Console.WriteLine(strText2);

Console.ReadKey();

}

}Hello, World!

Hello, World!

Page 45: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 45

Object Pool

Применение паттерна Object Pool может значительно повыситьпроизводительность системы; его использование наиболееэффективно в ситуациях, когда создание экземпляровнекоторого класса требует больших затрат, объекты в системесоздаются часто, но число создаваемых объектов в единицувремени ограничено.

Пулы объектов (известны также как пулы ресурсов)используются для управления кэшированием объектов. Клиент,имеющий доступ к пулу объектов может избежать созданияновых объектов, просто запрашивая в пуле уже созданныйэкземпляр. Пул объектов может быть растущим, когда приотсутствии свободных создаются новые объекты или cограничением количества создаваемых объектов.

Page 46: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 46

Реализация Object Pool на основе Singleton. Классы объектов

abstract class IObject {

protected string Text;

public virtual void Print() {

Console.WriteLine("The Object is: {0}", Text);

}

}

class Object1 : IObject {

public Object1() {

Text = "Object 1";

}

}

class Object2 : IObject {

public Object2() {

Text = "Object 2";

}

}

class Object3 : IObject {

public Object3() {

Text = "Object 3";

}

}

class Object4 : IObject {

public Object4() {

Text = "Object 4";

}

}

Page 47: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 47

Object Pool

class ObjectPool {

public static ObjectPool GetInstance(int size) {

if (instance == null) instance =

new ObjectPool(size);

return instance;

}

public IObject GetObject() {

for (int i = 0; i < poolSize; i++) {

if (!busyObjects[i]) {

busyObjects[i] = true;

return objectPool[i];

}

}

return null;

}

public void ReleaseObject(IObject obj) {

for (int i = 0; i < poolSize; i++) {

if (objectPool[i] == obj) {

busyObjects[i] = false;

}

}

}...

Page 48: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 48

Object Pool

private ObjectPool(int size) {

poolSize = size; objectPool = new IObject[poolSize];

busyObjects = new bool[poolSize]; Random rand = new Random(1000);

for (int i = 0; i < poolSize; i++) {

int iObjNumber = rand.Next()%4;

switch (iObjNumber) {

case 0: objectPool[i] = new Object1(); busyObjects[i] = false;

break;

case 1: objectPool[i] = new Object2(); busyObjects[i] = false;

break;

case 2: objectPool[i] = new Object3(); busyObjects[i] = false;

break;

case 3: objectPool[i] = new Object4(); busyObjects[i] = false;

break;

}

busyObjects[i] = false;

}

}

private IObject[] objectPool; private int poolSize;

private bool[] busyObjects; private static ObjectPool instance;

}

Page 49: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 49

Использование Object Poolclass Program {

static void Main(string[] args) {

ObjectPool op = ObjectPool.GetInstance(5);

IObject object1 = op.GetObject();

if (object1 != null) object1.Print(); else Console.WriteLine("The Object is: NULL");

IObject object2 = op.GetObject();

if (object2 != null) object2.Print(); else Console.WriteLine("The Object is: NULL");

IObject object3 = op.GetObject();

if (object3 != null) object3.Print(); else Console.WriteLine("The Object is: NULL");

IObject object4 = op.GetObject();

if (object4 != null) object4.Print(); else Console.WriteLine("The Object is: NULL");

IObject object5 = op.GetObject();

if (object5 != null) object5.Print(); else Console.WriteLine("The Object is: NULL");

IObject object6 = op.GetObject();

if (object6 != null) object6.Print(); else Console.WriteLine("The Object is: NULL");

IObject object7 = op.GetObject();

if (object7 != null) object7.Print(); else Console.WriteLine("The Object is: NULL");

op.ReleaseObject(object2);

IObject object8 = op.GetObject();

if (object8 != null) object8.Print(); else Console.WriteLine("The Object is: NULL");

Console.ReadKey();

}

}

Page 50: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 50

Результат

The Object is: Object 2

The Object is: Object 4

The Object is: Object 3

The Object is: Object 1

The Object is: Object 2

The Object is: NULL

The Object is: NULL

The Object is: Object 4

Page 51: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 51

Структурные шаблоны проектирования

–Adapter представляет собой программную обертку над ужесуществующими классами и предназначен для преобразования ихинтерфейсов к виду, пригодному для последующего использования вновом программном проекте.

–Bridge отделяет абстракцию от реализации так, что то и другоеможно изменять независимо.

–Composite группирует схожие объекты в древовидные структуры.Рассматривает единообразно простые и сложные объекты.

–Decorator используется для расширения функциональностиобъектов. Являясь гибкой альтернативой порождению классов,паттерн Decorator динамически добавляет объекту новыеобязанности.

–Facade предоставляет высокоуровневый унифицированныйинтерфейс к набору интерфейсов некоторой подсистемы, чтооблегчает ее использование.

–Flyweight использует разделение для эффективной поддержкимножества объектов.

–Proxy замещает другой объект для контроля доступа к нему.

Page 52: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 52

Адаптер

Паттерн Adapter, представляет собой программную обертку надсуществующими классами, преобразуя их интерфейсы к виду,пригодному для последующего использования.

Пусть класс, интерфейс которого нужно адаптировать к нужномувиду, имеет имя Adaptee. Для решения задачи преобразованияего интерфейса паттерн Adapter вводит следующую иерархиюклассов:

–Виртуальный базовый класс Target. Здесь объявляетсяпользовательский интерфейс подходящего вида. Только этотинтерфейс доступен для пользователя.

–Производный класс Adapter, реализующий интерфейс Target.В этом классе также имеется указатель или ссылка наэкземпляр Adaptee. Паттерн Adapter использует этотуказатель для перенаправления клиентских вызовов вAdaptee. Так как интерфейсы Adaptee и Target несовместимымежду собой, то эти вызовы обычно требуютпреобразования.

Page 53: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 53

Пример. Преобразование строки в структуру

class InputStringFullName

{

public string Text { get; set; }

public InputStringFullName()

{

Text = "";

}

public void Input()

{

Console.Write

("Input Full Name (Surname Name MiddleName): ");

Text = Console.ReadLine();

}

}

Page 54: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 54

Класс структуры

class FullName

{

public string Name { get; set; }

public string Surname { get; set; }

public string Middle { get; set; }

public FullName(string surname, string name, string middle)

{

Name = name; Surname = surname; Middle = middle;

}

public void Print()

{

Console.WriteLine(Name);

Console.WriteLine(Middle);

Console.WriteLine(Surname);

}

}

Page 55: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 55

Класс-адаптер

class FullNameAdapter : InputStringFullName

{

public FullNameAdapter(InputStringFullName stringFullName)

{

Text = stringFullName.Text;

}

public FullName GetFullName()

{

int iFirstSpace = Text.IndexOf(' ');

string strSurname = Text.Substring(0, iFirstSpace);

int iSecondSpace =

Text.Substring(iFirstSpace + 1).IndexOf(' ') + iFirstSpace + 1;

string strName =

Text.Substring(iFirstSpace, iSecondSpace - iFirstSpace);

string strMiddle = Text.Substring(iSecondSpace);

return new FullName(strSurname, strName, strMiddle);

}

}

Page 56: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 56

Использование адаптера

class Program

{

static void Main(string[] args)

{

InputStringFullName isfn = new InputStringFullName();

isfn.Input();

FullNameAdapter fna = new FullNameAdapter(isfn);

FullName fn = fna.GetFullName();

fn.Print();

Console.ReadKey();

}

}

Результат:Input Full Name (Surname Name MiddleName): Ivanov Ivan Ivanovich

Ivan

Ivanovich

Ivanov

Page 57: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 57

Паттерн проектирования «Мост»

Используется для того, чтобы разделять абстракцию и реализацию так,чтобы они могли изменяться независимо.

Page 58: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 58

Реализация. Классы реализаторов с общим интерфейсом

public interface Iimplementor {

void Operation();

}

class Implementor1 : Iimplementor {

void IImplementor.Operation() {

Console.WriteLine("Implementor 1");

}

}

class Implementor2 : Iimplementor {

void IImplementor.Operation() {

Console.WriteLine("Implementor 2");

}

}

Page 59: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 59

Класс-абстракция

class Abstraction

{

protected IImplementor implementor;

public Abstraction() { }

public void SetImplementor(IImplementor implementor)

{

this.implementor = implementor;

}

public void Operation()

{

implementor.Operation();

}

}

Page 60: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 60

Использование моста

class Program

{

static void Main(string[] args)

{

Abstraction abstr = new Abstraction();

abstr.SetImplementor(new Implementor1());

abstr.Operation();

abstr.SetImplementor(new Implementor2());

abstr.Operation();

Console.ReadKey();

}

}Результат:Implementor 1

Implementor 2

Page 61: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 61

Шаблоны поведения

Паттерн Chain of Responsibility позволяет обработать запроснескольким объектам-получателям. Получатели связываются в цепочку,и запрос передается по цепочке, пока не будет обработан каким-тообъектом. Паттерн Chain of Responsibility позволяет также избежатьжесткой зависимости между отправителем запроса и его получателями.

Паттерн Command преобразовывает запрос на выполнение действия вотдельный объект-команду. Это придает системе гибкость: позволяетосуществлять динамическую замену команд, использовать сложныесоставные команды, осуществлять отмену операций.

Паттерн Iterator предоставляет механизм обхода элементов составныхобъектов (коллекций) не раскрывая их внутреннего представления.

Паттерн Interpreter предназначен для решения повторяющихся задач,которые можно описать некоторым языком. Для этого паттернInterpreter описывает решаемую задачу в виде предложений этогоязыка, а затем интерпретирует их.

Паттерн Mediator инкапсулирует взаимодействие совокупностиобъектов в отдельный объект-посредник. Уменьшает степеньсвязанности взаимодействующих объектов - им не нужно хранитьссылки друг на друга.

Page 62: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 62

Шаблоны поведенияПаттерн Memento получает и сохраняет за пределами объекта еговнутреннее состояние так, чтобы позже можно было восстановитьобъект в таком же состоянии.

Паттерн Observer определяет зависимость "один-ко-многим" междуобъектами так, что при изменении состояния одного объекта всезависящие от него объекты уведомляются и обновляютсяавтоматически.

Паттерн State позволяет объекту изменять свое поведение взависимости от внутреннего состояния. Создается впечатление, чтообъект изменил свой класс. Паттерн State является объектно-ориентированной реализацией конечного автомата.

Если поведение системы настраивается согласно одному из некоторогомножества алгоритму, то применение паттерна Strategy переноситсемейство алгоритмов в отдельную иерархию классов, что позволяетзаменять один алгоритм другим в ходе выполнения программы. Крометого, такую систему проще расширять и поддерживать.

Паттерн Template Method определяет основу алгоритма и позволяетподклассам изменить некоторые шаги этого алгоритма без измененияего общей структуры.

Паттерн Visitor определяет операцию, выполняемую на каждомэлементе из некоторой структуры без изменения классов этих объектов.

Page 63: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 63

Паттерн Chain of Responsibility

Паттерн Chain of Responsibility позволяет избежать жесткойзависимости отправителя запроса от его получателя, при этомзапрос может быть обработан несколькими объектами.Объекты-получатели связываются в цепочку. Запроспередается по этой цепочке, пока не будет обработан.

Вводит конвейерную обработку для запроса с множествомвозможных обработчиков.

Объектно-ориентированный связанный список с рекурсивнымобходом.

Page 64: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 64

Общая схема паттерна

Клиент

Обработчик 1

Обработчик 2

Обработчик 3

Обработчик ...

Обработчик n

Page 65: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 65

Реализация цепочки. Классы событий

public abstract class IEvent{

public string EventType { get; set; }

}

class Event1 : IEvent {

public Event1() { EventType = "Event1"; }

}

class Event2 : IEvent {

public Event2() { EventType = "Event2"; }

}

class Event3 : IEvent {

public Event3() { EventType = "Event3"; }

}

class Event4 : IEvent {

public Event4() { EventType = "Event4"; }

}

class Event5 : IEvent {

public Event5() { EventType = "Event5"; }

}

class Event6 : IEvent {

public Event6() { EventType = "Event6"; }

}

Page 66: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 66

Базовый класс-обработчик

public abstract class BaseHandler {

public BaseHandler() { Next = null; }

public virtual void Handle(IEvent ev) {

if (PrivateEvent.EventType == ev.EventType)

{

Console.WriteLine("{0} successfully handled", PrivateEvent.EventType);

} else {

Console.WriteLine("Sending event to next Handler...");

if (Next != null)

Next.Handle(ev);

else

Console.WriteLine("Unknown event. Can't handle.");

}

}

protected void SetNextHandler(BaseHandler newHandler) {

Next = newHandler;

}

protected BaseHandler Next { get; set; }

protected IEvent PrivateEvent { get; set; }

}

Page 67: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 67

Классы-обработчики

class Handler5 : BaseHandler {

public Handler5() {

PrivateEvent = new Event5(); Next = null;

} }

class Handler4 : BaseHandler {

public Handler4() {

PrivateEvent = new Event4(); Next = new Handler5();

} }

class Handler3 : BaseHandler {

public Handler3() {

PrivateEvent = new Event3(); Next = new Handler4();

} }

class Handler2 : BaseHandler {

public Handler2() {

PrivateEvent = new Event2(); Next = new Handler3();

} }

class Handler1 : BaseHandler {

public Handler1() {

PrivateEvent = new Event1(); Next = new Handler2();

} }

Page 68: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 68

Класс тестового приложенияpublic class ChainApplication {

public ChainApplication() {

eventHandler = new Handler1(); Rand = new Random();

}

public void Run(int EventCount) {

for (int i = 0; i < EventCount; i++) {

HandleEvent(GenerateRandomEvent());

} }

private void HandleEvent(IEvent ev) {

eventHandler.Handle(ev);

}

private IEvent GenerateRandomEvent() {

IEvent result;

switch (Rand.Next(1,6)) {

case 0: result = new Event1(); break; case 1: result = new Event2(); break;

case 2: result = new Event3(); break; case 3: result = new Event4(); break;

case 4: result = new Event5(); break; default: result = new Event6(); break; }

Console.WriteLine("Generated event: {0}", result.EventType);

return result; }

private BaseHandler eventHandler;

private Random Rand;

}

Page 69: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 69

Результат цепочки ответственностей

class Program

{

static void Main(string[] args)

{

ChainApplication app = new ChainApplication();

app.Run(3);

Console.ReadKey();

}

}

Результат:Generated event: Event4

Sending event to next Handler...

Sending event to next Handler...

Sending event to next Handler...

Event4 successfully handled

Generated event: Event6

Sending event to next Handler...

Sending event to next Handler...

Sending event to next Handler...

Sending event to next Handler...

Sending event to next Handler...

Unknown event. Can't handle.

Generated event: Event5

Sending event to next Handler...

Sending event to next Handler...

Sending event to next Handler...

Sending event to next Handler...

Event5 successfully handled

Page 70: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 70

Команда

Паттерн Command преобразовывает запрос на выполнениедействия в отдельный объект-команду. Такая инкапсуляцияпозволяет передавать эти действия другим функциям иобъектам в качестве параметра, приказывая им выполнитьзапрошенную операцию. Команда – это объект, поэтому надней допустимы любые операции, что и над объектом.

Команда используется, если:

–Система управляется событиями. При появлении такогособытия (запроса) необходимо выполнить определеннуюпоследовательность действий.

–Необходимо параметризировать объекты выполняемымдействием, ставить запросы в очередь или поддерживатьоперации отмены и повтора действий.

–Нужен объектно-ориентированный аналог функцииобратного вызова в процедурном программировании.

Page 71: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 71

Пример. Интерфейс «Игра»

public interface IGame

{

void New();

void Start();

void Pause();

void Resume();

void Finish();

void Break();

void BreakAndFinish();

void BreakAndStart();

}

Page 72: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 72

Реализация интерфейса

public class SomeGame : Igame {

void IGame.New() {

Console.WriteLine("New Game."); }

void IGame.Start() {

Console.WriteLine("Game Started."); }

void IGame.Pause() {

Console.WriteLine("Game Paused."); }

void IGame.Resume() {

Console.WriteLine("Game Resumed."); }

void IGame.Finish() {

Console.WriteLine("Game Finished."); }

void IGame.Break() {

Console.WriteLine("Game Breaked."); }

void IGame.BreakAndFinish() {

Console.WriteLine("Game Breaked.");

Console.WriteLine("Game Finished."); }

void IGame.BreakAndStart() {

Console.WriteLine("Game Breaked.");

Console.WriteLine("New Game.");

Console.WriteLine("Game Started."); }

}

Page 73: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 73

Классы команд

public class Icommand {

public ICommand(IGame game) { Game = game; }

public virtual void ExecuteCommand() { }

public IGame Game { get; set; }

}

class NewCommand : Icommand {

public NewCommand(IGame game) : base(game) { }

public override void ExecuteCommand()

{

Console.WriteLine("Executing New Command...");

Game.New();

}

}

class StartCommand : Icommand {

public StartCommand(IGame game) : base(game) { }

public override void ExecuteCommand()

{

Console.WriteLine("Executing Start Command...");

Game.Start();

}

}

Page 74: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 74

Классы команд

class PauseCommand : ICommand{

public PauseCommand(IGame game) : base(game) { }

public override void ExecuteCommand() {

Console.WriteLine("Executing Pause Command...");

Game.Pause();

}

}

class ResumeCommand : ICommand{

public ResumeCommand(IGame game) : base(game) { }

public override void ExecuteCommand() {

Console.WriteLine("Executing Resume Command...");

Game.Resume();

}

}

class FinishCommand : ICommand{

public FinishCommand(IGame game) : base(game) { }

public override void ExecuteCommand() {

Console.WriteLine("Executing Finish Command...");

Game.Finish();

}

}

Page 75: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 75

Классы команд

class BreakCommand : ICommand{

public BreakCommand(IGame game) : base(game) { }

public override void ExecuteCommand() {

Console.WriteLine("Executing Break Command...");

Game.Break();

}

}

class BreakAndFinishCommand : ICommand{

public BreakAndFinishCommand(IGame game) : base(game) { }

public override void ExecuteCommand() {

Console.WriteLine("Executing Break And Finish Command...");

Game.BreakAndFinish();

}

}

class BreakAndStartCommand : ICommand{

public BreakAndStartCommand(IGame game) : base(game) { }

public override void ExecuteCommand() {

Console.WriteLine("Executing Break And Start Command...");

Game.BreakAndStart();

}

}

Page 76: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 76

Использование команд

class Program

{

static void Main(string[] args)

{

IGame someGame = new SomeGame();

ICommand[] commands = new ICommand[10];

commands[0] = new NewCommand(someGame);

commands[1] = new StartCommand(someGame);

commands[2] = new BreakCommand(someGame);

commands[3] = new NewCommand(someGame);

commands[4] = new StartCommand(someGame);

commands[5] = new BreakAndStartCommand(someGame);

commands[6] = new PauseCommand(someGame);

commands[7] = new ResumeCommand(someGame);

commands[8] = new PauseCommand(someGame);

commands[9] = new BreakAndFinishCommand(someGame);

for (int i = 0; i < 10; i++)

{

commands[i].ExecuteCommand();

}

Console.ReadKey();

}

}

Результат:Executing New Command...

New Game.

Executing Start Command...

Game Started.

Executing Break Command...

Game Breaked.

Executing New Command...

New Game.

Executing Start Command...

Game Started.

Executing Break And Start Command...

Game Breaked.

New Game.

Game Started.

Executing Pause Command...

Game Paused.

Executing Resume Command...

Game Resumed.

Executing Pause Command...

Game Paused.

Executing Break And Finish Command...

Game Breaked.

Game Finished.

Page 77: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 77

Паттерн Iterator

Назначение паттерна Iterator

• Предоставляет способ последовательного доступа ко всемэлементам составного объекта, не раскрывая его внутреннегопредставления.

• Абстракция в стандартных библиотеках C++ и Java, позволяющаяразделить классы коллекций и алгоритмов.

• Придает обходу коллекции "объектно-ориентированный статус".

• Полиморфный обход.

Page 78: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 78

Интерфейсы

public interface IIterator

{

object Next();

object First();

bool Finished();

object Current();

}

public interface IIterCollection

{

IIterator GetIterator();

}

Page 79: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 79

Реализация коллекции

public class IterCollection: IIterCollection

{

private ArrayList items = new ArrayList();

IIterator IIterCollection.GetIterator()

{

return new Iterator(this);

}

public object Get(int i)

{

return items[i];

}

public int GetCount()

{

return items.Count;

}

}

Page 80: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 80

Реализация итератораpublic class Iterator : IIterator

{

private IterCollection collection;

private int current;

public Iterator(IterCollection col)

{

collection = col;

current = 0;

}

object IIterator.First()

{

return collection.Get(0);

}

object IIterator.Current()

{

return collection.Get(current);

}

bool IIterator.Finished()

{

return (current >= collection.GetCount());

}

object IIterator.Next()

{

return collection.Get(current++);

}

}

Page 81: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 81

Использование

class Program

{

static void Main(string[] args)

{

IIterCollection ic = new IterCollection(10);

IIterator iter = ic.GetIterator();

while (!iter.Finished())

{

Console.WriteLine(iter.Next());

}

Console.ReadKey();

}

}

0

7

5

2

9

9

5

0

5

9

Page 82: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 82

Альтернативная реализацияpublic class SquareCollection : IEnumerable<int> {

private int[][] items;

public SquareCollection(int number) {

Random rand = new Random();

this.items = new int[number][];

for (int i = 0; i < number; i++) {

int[] item = new int[number];

for (int j = 0; j < number; j++) {

item[j] = rand.Next() % 10;

}

this.items[i] = item;

}

}

public IEnumerator<int> GetEnumerator() {

for (int i = 0; i < items.Length; i++) {

for (int j = items[i].Length - 1; j >= 0; j--) {

yield return items[i][j];

}

}

}

IEnumerator IEnumerable.GetEnumerator() {

return GetEnumerator();

}

}

Page 83: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 83

Использование

class Program

{

static void Main(string[] args)

{

SquareCollection sc = new SquareCollection(10);

foreach (var item in sc)

{

Console.WriteLine(item);

}

Console.ReadKey();

}

}

5

0

1

5

2

6

7

1

3

9

5

0

3

8

2

...

Page 84: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 84

Паттерн Memento (Хранитель)

Назначение паттерна Memento:

• Не нарушая инкапсуляции, паттерн Memento получает и сохраняетза пределами объекта его внутреннее состояние так, чтобы позжеможно было восстановить объект в таком же состоянии.

• Является средством для инкапсуляции "контрольных точек"программы.

• Паттерн Memento придает операциям "Отмена" (undo) или "Откат"(rollback) статус "полноценного объекта".

Паттерн проектирования Memento определяет трех различныхучастников:

• Originator (хозяин) - объект, умеющий создавать хранителя, атакже знающий, как восстановить свое внутреннее состояние изхранителя.

• Caretaker (смотритель) - объект, который знает, почему и когдахозяин должен сохранять и восстанавливать себя.

• Memento (хранитель) - "ящик на замке", который пишется ичитается хозяином и за которым присматривает смотритель.

Page 85: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 85

Класс Memento и интерфейс IOriginator

class Memento

{

public string Name { get; set; }

public string Surname { get; set; }

public string MiddleName { get; set; }

}

public interface IOriginator

{

object GetMemento();

void SetMemento(object memento);

}

Page 86: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 86

Класс для состояние, которого надо запомнитьclass FullNameClass: IOriginator

{

public string Name { get; set; }

public string Surname { get; set; }

public string MiddleName { get; set; }

public FullNameClass(string name, string surname, string middle) {

Name = name; Surname = surname; MiddleName = middle;

}

public void Print() {

Console.WriteLine("Name={0} Surname={1} Middle={2}", Name, Surname, MiddleName);

}

object IOriginator.GetMemento() {

return new Memento

{ Name = this.Name, Surname = this.Surname, MiddleName = this.MiddleName };

}

void IOriginator.SetMemento(object memento){

if (memento is Memento)

{

var mem = memento as Memento;

Name = mem.Name;

Surname = mem.Surname;

MiddleName = mem.MiddleName;

}

}

}

Page 87: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 87

Класс «Смотритель»

public class Caretaker

{

private object memento;

public void SaveState(IOriginator originator)

{

memento = originator.GetMemento();

}

public void RestoreState(IOriginator originator)

{

originator.SetMemento(memento);

}

}

Page 88: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 88

Использование

class Program

{

static void Main(string[] args)

{

FullNameClass fnc = new

FullNameClass("Ivan", "Ivanov", "Ivanovich");

Caretaker ct = new Caretaker();

fnc.Print();

ct.SaveState(fnc);

fnc = new FullNameClass("Petr", "Petrov", "Petrovich");

fnc.Print();

ct.RestoreState(fnc);

fnc.Print();

}

}

Name=Ivan Surname=Ivanov Middle=Ivanovich

Name=Petr Surname=Petrov Middle=Petrovich

Name=Ivan Surname=Ivanov Middle=Ivanovich

Page 89: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 89

Паттерн «Стратегия»

Паттерн Стратегия (Strategy) предназначен для определениясемейства алгоритмов и инкапсуляции каждого из них иобеспечения их взаимозаменяемости.

Переносит в отдельную иерархию классов все детали,связанные с реализацией алгоритмов.

Page 90: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 90

Пример

public abstract class IStrategy

{

public abstract void Use();

protected void WakeUp() { Console.WriteLine("Wake up."); }

protected void Shower() { Console.WriteLine("Take shower."); }

protected void Dress() { Console.WriteLine("Dress."); }

protected void GoToBusStop() { Console.WriteLine("Go to bus stop."); }

protected void Wait() { Console.WriteLine("Wait."); }

protected void Arrive() { Console.WriteLine("Arrive."); }

protected void DoWork() { Console.WriteLine("Do work."); }

protected void DoExercises() { Console.WriteLine("Do exercises."); }

protected void Walk() { Console.WriteLine("Walk."); }

protected void GoOut() { Console.WriteLine("Go out."); }

protected void GoToPark() { Console.WriteLine("Go to park."); }

}

Page 91: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 91

Классы конкретных стратегий

class GoToWorkStrategy : Istrategy {

public override void Use()

{

WakeUp(); Shower(); Dress(); GoOut();

GoToBusStop(); Wait(); Arrive(); DoWork();

}

}

class GoWalkStrategy : Istrategy {

public override void Use()

{

GoOut(); GoToPark(); Walk();

}

}

class GoToGymStrategy : Istrategy {

public override void Use()

{

GoOut(); GoToBusStop(); Arrive(); DoExercises();

}

}

Page 92: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 92

Клиент стратегий

public abstract class IStrategyClient

{

public abstract void UseStrategy();

public void SetStrategy(IStrategy st) { strategy = st; }

protected IStrategy strategy;

}

class StrategyClient1 : IStrategyClient

{

public StrategyClient1() { }

public override void UseStrategy()

{

strategy.Use();

}

}

Page 93: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 93

Использование стратегий

class Program

{

static void Main(string[] args)

{

IStrategyClient stClient = new StrategyClient1();

stClient.SetStrategy(new GoToWorkStrategy());

stClient.UseStrategy();

Console.WriteLine();

stClient.SetStrategy(new GoToGymStrategy());

stClient.UseStrategy();

Console.WriteLine();

stClient.SetStrategy(new GoWalkStrategy());

stClient.UseStrategy();

Console.ReadKey();

}

}

Wake up.

Take shower.

Dress.

Go out.

Go to bus stop.

Wait.

Arrive.

Do work.

Go out.

Go to bus stop.

Arrive.

Do exercises.

Go out.

Go to park.

Walk.

Page 94: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 94

Анонимные методы

Новый класс стратегий:

public delegate void StrategyDelegate();

public abstract class IStrategyClient

{

public abstract void UseStrategy();

public StrategyDelegate Strategy { get; set; }

}

class StrategyClient1 : IStrategyClient

{

public StrategyClient1() { }

public override void UseStrategy()

{

Strategy();

}

}

Page 95: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 95

Использование анонимных методовclass Program

{

static void Main(string[] args)

{

IStrategyClient stClient = new StrategyClient1();

IStrategy goWork = new GoToWorkStrategy();

IStrategy goGym = new GoToGymStrategy();

IStrategy goWalk = new GoWalkStrategy();

stClient.Strategy = delegate {

Console.WriteLine("Anonymous Method:");

goWork.Use();

Console.WriteLine(); };

stClient.UseStrategy();

stClient.Strategy = delegate {

Console.WriteLine("Anonymous Method:");

goGym.Use(); Console.WriteLine(); };

stClient.UseStrategy();

stClient.Strategy = delegate {

Console.WriteLine("Anonymous Method:");

goWalk.Use(); Console.WriteLine(); };

stClient.UseStrategy();

Console.ReadKey();

}

}

Anonymous Method:

Wake up.

Take shower.

Dress.

Go out.

Go to bus stop.

Wait.

Arrive.

Do work.

Anonymous Method:

Go out.

Go to bus stop.

Arrive.

Do exercises.

Anonymous Method:

Go out.

Go to park.

Walk.

Page 96: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 96

Шаблон проектирования «Visitor»

Паттерн Visitor определяет операцию, выполняемую на каждомэлементе из некоторой структуры без изменения классов этихобъектов.

• Паттерн Visitor определяет операцию, выполняемую на каждомэлементе из некоторой структуры. Позволяет, не изменяя классыэтих объектов, добавлять в них новые операции.

Применение расширяющих методов значительно упрощает реализациюэтого паттерна.

Page 97: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 97

Классы «компонентов»

public class SomeClass1

{

public SomeClass1(int c) { SomeProperty1 = c; }

public int SomeProperty1 { get; set; }

}

public class SomeClass2

{

public SomeClass2(int c) { SomeProperty2 = c; }

public int SomeProperty2 { get; set; }

}

public class SomeClass3

{

public SomeClass3(int c) { SomeProperty3 = c; }

public int SomeProperty3 { get; set; }

}

Page 98: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 98

Класс-посетитель

public static class Visitor

{

public static void Visit(this SomeClass1 sc1)

{

Console.WriteLine(sc1.SomeProperty1);

}

public static void Visit(this SomeClass2 sc2)

{

Console.WriteLine(sc2.SomeProperty2);

}

public static void Visit(this SomeClass3 sc3)

{

Console.WriteLine(sc3.SomeProperty3);

}

}

Page 99: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 99

Использование

class Program

{

static void Main(string[] args)

{

SomeClass1 c1 = new SomeClass1(1);

SomeClass2 c2 = new SomeClass2(2);

SomeClass3 c3 = new SomeClass3(3);

c1.Visit(); c2.Visit(); c3.Visit();

Console.ReadKey();

}

}

1

2

3

Page 100: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 100

Расширяющие методы

Расширяющие методы (методы расширения) позволяют "добавлять" методы всуществующие типы без создания нового производного типа, перекомпиляции илииного изменения исходного типа.

Расширяющие методы являются особым видом статического метода, но онивызываются, как если бы они были методами экземпляра в расширенном типе. Дляклиентского кода, написанного на языках C#, нет видимого различия междувызовом метода расширения и вызовом методов, фактически определенных в типе.

public static class MyExtensions

{

public static int WordCount(this String str)

{

return str.Split(new char[] { ' ', '.', '?' },

StringSplitOptions.RemoveEmptyEntries).Length;

}

}

Методы расширения определяются как статические методы, но вызываются спомощью синтаксиса обращения к методу экземпляра. Их первый параметропределяет, с каким типом оперирует метод, и перед параметром идетмодификатор this. Методы расширения находятся в области действия, только еслипространство имен было явно импортировано в исходный код с помощьюдирективы using.

Page 101: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 101

Пример расширяющих методов

public static class ExtensionMethods

{

public static double Angle(this Complex compl)

{

if ((compl.Re == 0) && (compl.Im >= 0)) {

return Math.PI / 2;

}

if ((compl.Re == 0) && (compl.Im < 0)) {

return 3 * Math.PI / 2;

}

return Math.Atan(compl.Im / compl.Re);

}

}

class Program

{

static void Main(string[] args)

{

Complex c1 = new Complex(1,2);

Console.WriteLine(c1);

double angle = c1.Angle();

Console.WriteLine(angle);

Console.ReadKey();

}

}

Page 102: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 102

Некоторые архитектурные паттерны

Page 103: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 103

MVC

Шаблон проектированияMVC разделяет работувеб-приложения на триотдельныефункциональные роли:

• модель данных(model)

• пользовательскийинтерфейс (view)

• управляющуюлогику (controller)

Таким образом, изменения,вносимые в один изкомпонентов, оказываютминимально возможноевоздействие на другиекомпоненты.

Page 104: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 104

MVP

• Модель (model)представляет собой интерфейс,определяющий данные дляотображения или участвующие впользовательском интерфейсеиным образом

• Вид (view) - это интерфейс,который отображает данные(модель) и маршрутизируетпользовательские команды (илисобытия) Presenter-у, чтобы тотдействовал над этими данными.

• Presenter действует надмоделью и видом. Он извлекаетданные из хранилища (модели), иформатирует их для отображенияв Виде (view). Так же реализуетобработку событий вида.

Page 105: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 105

MVC vs MVP

Page 106: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 106

Архитектурный паттерн MVVM

• Модель (Model), так же, как вклассическом паттерне MVC, Модельпредставляет собой фундаментальныеданные, необходимые для работыприложения (классы, структуры).

• Вид/Представление (View) также, как в классическом паттерне MVC,Вид — это графический интерфейс, тоесть окно, кнопки и.т.п.

• Модель вида (ViewModel, чтоозначает «Model of View») является содной стороны абстракцией Вида, а сдругой предоставляет обертку данныхиз Модели, которые подлежатсвязыванию. То есть она содержитМодель, которая преобразована кВиду, а так же содержит в себекоманды, которыми можетпользоваться Вид, чтобы влиять наМодель.

Page 107: Общие темы. Тема 02.

http://www.slideshare.net/IgorShkulipa 107

MVVM