Общие темы. Тема 02.
-
Upload
igor-shkulipa -
Category
Education
-
view
90 -
download
1
Transcript of Общие темы. Тема 02.
Темы лекции: SOLID. Паттерны проектирования
Игорь Шкулипа, к.т.н.
http://www.slideshare.net/IgorShkulipa 3
SOLID. Принципы проектирования классов
SOLID – это акроним названий пяти основных принциповпроектирования классов, сформулированных Робертом Мартином:
•Single responsibility (принцип одной ответственности),
•Open for extension and closed for modification (принципоткрытости/закрытости, или открытость для расширения изакрытость для модификации),
•Liskov substitution (принцип подстановки Лисков),
•Interface segregation (принцип разделения интерфейса),
•Dependency inversion (принцип инверсии зависимостей).
http://www.slideshare.net/IgorShkulipa 4
Single Responsibility
Принцип единственной ответственности (Single Responsibility Principle)часто определяют так: у объекта должна быть только одна причина дляизменения; чем больше файл или класс, тем труднее достичь этойцели.
Этот принцип говорит о том, что по-хорошему каждый класс долженрешать только одну задачу. Это совсем не значит, что в класседолжен быть всего один метод. Это означает, что методы классадолжны быть связаны одной общей целью.
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) { }
}
http://www.slideshare.net/IgorShkulipa 6
Open for Extension and Closed for Modification
Объекты проектирования (классы, функции, модули и т.д.) должны бытьоткрыты для расширения, но закрыты для модификации.
Этот принцип говорит о том, что классы нужно проектировать так, чтобывпоследствии иметь возможность изменять поведение класса, неизменяя его код.
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) { }
}
http://www.slideshare.net/IgorShkulipa 8
Liskov Substitution
Функции, которые используют ссылки на базовые классы, должны иметьвозможность использовать объекты производных классов, не зная обэтом.
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);
//...
}
}
http://www.slideshare.net/IgorShkulipa 10
Interface Segregation
Принцип изоляции/разделения интерфейса говорит о том, что клиент недолжен вынужденно зависеть от элементов интерфейса, которые он неиспользует.
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() { }
}
http://www.slideshare.net/IgorShkulipa 12
Dependency Inversion
•Модули верхних уровней не должны зависеть от модулей нижнихуровней.
•Оба типа модулей должны зависеть от абстракций.
•Абстракции не должны зависеть от деталей.
•Детали должны зависеть от абстракций.
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();
}
}
http://www.slideshare.net/IgorShkulipa 14
Паттерны проектирования
http://www.slideshare.net/IgorShkulipa 15
Паттерны (шаблоны проектирования)
Паттерн описывает задачу, которая снова и снова возникает в работе, а так жепринцип ее решения, причем таким образом, что это решение можно потомиспользовать много раз, ничего не изобретая заново.
В общем случае паттерн состоит из четырех основных элементов:
Имя. Присваивание паттернам имен позволяет проектировать на более высокомуровне абстракции. С помощью имен паттернов можно вести общение сколлегами. Назначение паттернам имен упрощает общение в профессиональнойсреде.
Задача - это описание того, когда следует применять паттерн. Необходимосформулировать задачу и ее контекст. Может описываться конкретная проблемапроектирования, например способ представления алгоритмов в виде объектов.Так же задача может включать перечень условий, при выполнении которых имеетсмысл применять данный паттерн.
Решение представляет собой описание элементов дизайна, отношений междуними, функций каждого элемента. Конкретный дизайн или реализация не имеютсяввиду, поскольку паттерн – это шаблон, применимый в самых разных ситуациях.
Результаты - это следствия применения паттерна и разного рода компромиссы.Хотя при описании проектных решений о последствиях часто не упоминают, знатьо них необходимо, чтобы можно было выбрать между различными вариантами иоценить преимущества и недостатки данного паттерна.
http://www.slideshare.net/IgorShkulipa 16
Паттерны (шаблоны проектирования)
Паттерн описывает задачу, которая снова и снова возникает в работе, а так жепринцип ее решения, причем таким образом, что это решение можно потомиспользовать много раз, ничего не изобретая заново.
В общем случае паттерн состоит из четырех основных элементов:
Имя. Присваивание паттернам имен позволяет проектировать на более высокомуровне абстракции. С помощью имен паттернов можно вести общение сколлегами. Назначение паттернам имен упрощает общение в профессиональнойсреде.
Задача - это описание того, когда следует применять паттерн. Необходимосформулировать задачу и ее контекст. Может описываться конкретная проблемапроектирования, например способ представления алгоритмов в виде объектов.Так же задача может включать перечень условий, при выполнении которых имеетсмысл применять данный паттерн.
Решение представляет собой описание элементов дизайна, отношений междуними, функций каждого элемента. Конкретный дизайн или реализация не имеютсяввиду, поскольку паттерн – это шаблон, применимый в самых разных ситуациях.
Результаты - это следствия применения паттерна и разного рода компромиссы.Хотя при описании проектных решений о последствиях часто не упоминают, знатьо них необходимо, чтобы можно было выбрать между различными вариантами иоценить преимущества и недостатки данного паттерна.
http://www.slideshare.net/IgorShkulipa 17
Классификация паттернов
Паттерны проектирования программных систем делятся наследующие категории:
Архитектурные паттерны. Описывают структурную схемупрограммной системы в целом. В данной схеме указываютсяотдельные функциональные составляющие системы,называемые подсистемами, а также взаимоотношения междуними.
Паттерны проектирования. описывают схемы детализациипрограммных подсистем и отношений между ними, при этом онине влияют на структуру программной системы в целом исохраняют независимость от реализации языкапрограммирования.
Идиомы - низкоуровневые паттерны, имеют дело с вопросамиреализации какой-либо проблемы с учетом особенностейданного языка программирования.
http://www.slideshare.net/IgorShkulipa 18
Паттерны проектирования
Паттерны проектирования делятся на следующие категории:
Порождающие - шаблоны проектирования, которыеабстрагируют процесс создания объектов. Они позволяютсделать систему независимой от способа создания, композициии представления объектов.
Структурные - шаблоны проектирования, в которыхрассматривается вопрос о том, как из классов и объектовобразуются более крупные структуры.
Поведенческие - шаблоны проектирования, определяющиеалгоритмы и способы реализации взаимодействия различныхобъектов и классов.
http://www.slideshare.net/IgorShkulipa 19
Порождающие паттерны
•Singleton (Одиночка) - контролирует создание единственногоэкземпляра некоторого класса и предоставляет доступ к нему.
•Factory Method (Фабричный метод) - В его классическом вариантевводится полиморфный класс Factory, в котором определяетсяинтерфейс фабричного метода, а ответственность за создание объектовконкретных классов переносится на производные от Factory классы, вкоторых этот метод переопределяется.
•Abstract Factory (Абстрактная фабрика) - использует несколькофабричных методов и предназначен для создания целого семейства илигруппы взаимосвязанных объектов.
•Builder (Строитель) - определяет процесс поэтапного конструированиясложного объекта, в результате которого могут получаться разныепредставления этого объекта.
•Prototype (Прототип) - создает новые объекты с помощью прототипов.Прототип - некоторый объект, умеющий создавать по запросу копиюсамого себя.
•Object Pool (Пул объектов) - используется в случае, когда созданиеобъекта требует больших затрат или может быть создано толькоограниченное количество объектов некоторого класса.
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();
}
}
http://www.slideshare.net/IgorShkulipa 21
Применение Singleton
Применяется, когда нужен только один экземпляр класса.Например для хранения глобальной конфигурации системы,для ведения логов, связи с базой данных и т.д.
Основное преимущество перед глобальными переменными втом, что экземпляр класса создается не при инициализациипрограммы, а по первому требованию.
http://www.slideshare.net/IgorShkulipa 22
Factory Method
Паттерн Factory Method может быть полезным в решенииследующих задач:
1. Система должна оставаться расширяемой путем добавленияобъектов новых типов. Непосредственное использованиеоператора new является нежелательным, так как в этомслучае код создания объектов с указанием конкретных типовможет получиться разбросанным по всему приложению. Тогдатакие операции как добавление в систему объектов новыхтипов или замена объектов одного типа на другой будутзатруднительными. Паттерн Factory Method позволяет системеоставаться независимой как от самого процесса порожденияобъектов, так и от их типов.
2. Заранее известно, когда нужно создавать объект, нонеизвестен его тип.
http://www.slideshare.net/IgorShkulipa 23
Описание паттерна Factory Method
Для того, чтобы система оставалась независимой от различных типовобъектов, паттерн Factory Method использует механизм полиморфизма -классы всех конечных типов наследуются от одного абстрактногобазового класса, предназначенного для полиморфного использования. Вэтом базовом классе определяется единый интерфейс, через которыйпользователь будет оперировать объектами конечных типов.
Для обеспечения относительно простого добавления в систему новых типовпаттерн Factory Method локализует создание объектов конкретных типов вспециальном классе-фабрике. Методы этого класса, посредством которыхсоздаются объекты конкретных классов, называются фабричными.
Существуют две разновидности паттерна Factory Method:
Обобщенный конструктор, когда в том же самом полиморфном базовомклассе, от которого наследуются производные классы всех создаваемых всистеме типов, определяется статический фабричный метод. В качествепараметра в этот метод должен передаваться идентификатор типасоздаваемого объекта.
Классический вариант фабричного метода, когда интерфейс фабричныхметодов объявляется в независимом классе-фабрике, а их реализацияопределяется конкретными подклассами этого класса.
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";
}
}
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();
}
}
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
http://www.slideshare.net/IgorShkulipa 27
Преимущества и недостатки
Преимущества паттерна Factory Method:
–Создает объекты разных типов, позволяя системе оставатьсянезависимой как от самого процесса создания, так и от типовсоздаваемых объектов.
Недостатки паттерна Factory Method:
–В случае классического варианта паттерна даже дляпорождения единственного объекта необходимо создаватьсоответствующую фабрику
http://www.slideshare.net/IgorShkulipa 28
Abstract Factory
Паттерн Abstract Factory стоит использовать, когда:
–Система должна оставаться независимой как от процессасоздания новых объектов, так и от типов порождаемыхобъектов. Непосредственное использование оператора new вкоде приложения нежелательно.
–Необходимо создавать группы или семействавзаимосвязанных объектов, исключая возможностьодновременного использования объектов из разных семействв одном контексте.
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";
}
}
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";
}
}
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();
}
}
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
http://www.slideshare.net/IgorShkulipa 33
Паттерн «Прототип»
Использует для создания новых объектов копию самого себя.
Паттерн Prototype (прототип) можно использовать в следующихслучаях:
–Система должна оставаться независимой как от процессасоздания новых объектов, так и от типов порождаемыхобъектов. Непосредственное использование оператора new вкоде приложения считается нежелательным.
–Необходимо создавать объекты, точные классы которыхстановятся известными уже на стадии выполненияпрограммы.
http://www.slideshare.net/IgorShkulipa 34
Интерфейс ICloneable
Поддерживает копирование, при котором создается новый экземпляркласса с тем же значением, что и у существующего экземпляра.
Метод Clone() создает новый объект, являющийся копией текущегоэкземпляра.
Метод MemberwiseClone для создания неполной копии создает новыйобъект, а затем копирует в него нестатические поля текущего объекта.Если поле относится к типу значения, выполняется побитовоекопирование полей. Если поле относится к ссылочному типу,копируются ссылки, а не объекты, на которые они указывают;следовательно, ссылки в исходном объекте и его клоне указывают наодин и тот же объект.
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; ;
}
}
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
http://www.slideshare.net/IgorShkulipa 37
Паттерн Builder
Паттерн Builder может помочь в решении следующих задач:
–В системе могут существовать сложные объекты, созданиекоторых за одну операцию затруднительно или невозможно.Требуется поэтапное построение объектов с контролемрезультатов выполнения каждого этапа.
–Данные должны иметь несколько представлений. Например,если есть некоторый исходный документ в формате RTF (RichText Format), в общем случае содержащий текст,графические изображения и служебную информацию оформатировании (размер и тип шрифтов, отступы и др.).Если этот документ в формате RTF преобразовать в другиеформаты (например, Microsoft Word или простой ASCII-текст),то полученные документы и будут представлениямиисходных данных.
http://www.slideshare.net/IgorShkulipa 38
Описание паттерна Builder
Паттерн Builder отделяет алгоритм поэтапного конструированиясложного объекта от его внешнего представления так, что спомощью одного и того же алгоритма можно получать разныепредставления этого объекта.
Для этого паттерн Builder определяет алгоритм поэтапногосоздания продукта в специальном классе Director(распорядитель), а ответственность за координацию процессасборки отдельных частей продукта возлагает на иерархиюклассов Builder. В этой иерархии базовый класс Builderобъявляет интерфейс для построения отдельных частейпродукта, а соответствующие подклассы конкретныхстроителей их реализуют подходящим образом, например,создают или получают нужные ресурсы, сохраняютпромежуточные результаты, контролируют результатывыполнения операций.
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);
}
}
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;
} }
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();
}
}
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
http://www.slideshare.net/IgorShkulipa 43
StringBuilder
Предоставляет изменяемую строку символов.
[SerializableAttribute]
[ComVisibleAttribute(true)]
public sealed class StringBuilder : ISerializable
Операция объединения объекта String всегда создает новый объект изсуществующей строки и новых данных. Объект StringBuilderподдерживает буфер для размещения и конкатенации новых данных.Новые данные добавляются в имеющийся буфер только в том случае,если в нем имеется достаточное свободное пространство для ихразмещения, в противном случае выделяется новый буфердостаточного размера, данные из оригинального буфера копируются вдругой буфер, и новые данные добавляются уже в новый буфер.
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!
http://www.slideshare.net/IgorShkulipa 45
Object Pool
Применение паттерна Object Pool может значительно повыситьпроизводительность системы; его использование наиболееэффективно в ситуациях, когда создание экземпляровнекоторого класса требует больших затрат, объекты в системесоздаются часто, но число создаваемых объектов в единицувремени ограничено.
Пулы объектов (известны также как пулы ресурсов)используются для управления кэшированием объектов. Клиент,имеющий доступ к пулу объектов может избежать созданияновых объектов, просто запрашивая в пуле уже созданныйэкземпляр. Пул объектов может быть растущим, когда приотсутствии свободных создаются новые объекты или cограничением количества создаваемых объектов.
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";
}
}
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;
}
}
}...
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;
}
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();
}
}
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
http://www.slideshare.net/IgorShkulipa 51
Структурные шаблоны проектирования
–Adapter представляет собой программную обертку над ужесуществующими классами и предназначен для преобразования ихинтерфейсов к виду, пригодному для последующего использования вновом программном проекте.
–Bridge отделяет абстракцию от реализации так, что то и другоеможно изменять независимо.
–Composite группирует схожие объекты в древовидные структуры.Рассматривает единообразно простые и сложные объекты.
–Decorator используется для расширения функциональностиобъектов. Являясь гибкой альтернативой порождению классов,паттерн Decorator динамически добавляет объекту новыеобязанности.
–Facade предоставляет высокоуровневый унифицированныйинтерфейс к набору интерфейсов некоторой подсистемы, чтооблегчает ее использование.
–Flyweight использует разделение для эффективной поддержкимножества объектов.
–Proxy замещает другой объект для контроля доступа к нему.
http://www.slideshare.net/IgorShkulipa 52
Адаптер
Паттерн Adapter, представляет собой программную обертку надсуществующими классами, преобразуя их интерфейсы к виду,пригодному для последующего использования.
Пусть класс, интерфейс которого нужно адаптировать к нужномувиду, имеет имя Adaptee. Для решения задачи преобразованияего интерфейса паттерн Adapter вводит следующую иерархиюклассов:
–Виртуальный базовый класс Target. Здесь объявляетсяпользовательский интерфейс подходящего вида. Только этотинтерфейс доступен для пользователя.
–Производный класс Adapter, реализующий интерфейс Target.В этом классе также имеется указатель или ссылка наэкземпляр Adaptee. Паттерн Adapter использует этотуказатель для перенаправления клиентских вызовов вAdaptee. Так как интерфейсы Adaptee и Target несовместимымежду собой, то эти вызовы обычно требуютпреобразования.
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();
}
}
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);
}
}
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);
}
}
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
http://www.slideshare.net/IgorShkulipa 57
Паттерн проектирования «Мост»
Используется для того, чтобы разделять абстракцию и реализацию так,чтобы они могли изменяться независимо.
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");
}
}
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();
}
}
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
http://www.slideshare.net/IgorShkulipa 61
Шаблоны поведения
Паттерн Chain of Responsibility позволяет обработать запроснескольким объектам-получателям. Получатели связываются в цепочку,и запрос передается по цепочке, пока не будет обработан каким-тообъектом. Паттерн Chain of Responsibility позволяет также избежатьжесткой зависимости между отправителем запроса и его получателями.
Паттерн Command преобразовывает запрос на выполнение действия вотдельный объект-команду. Это придает системе гибкость: позволяетосуществлять динамическую замену команд, использовать сложныесоставные команды, осуществлять отмену операций.
Паттерн Iterator предоставляет механизм обхода элементов составныхобъектов (коллекций) не раскрывая их внутреннего представления.
Паттерн Interpreter предназначен для решения повторяющихся задач,которые можно описать некоторым языком. Для этого паттернInterpreter описывает решаемую задачу в виде предложений этогоязыка, а затем интерпретирует их.
Паттерн Mediator инкапсулирует взаимодействие совокупностиобъектов в отдельный объект-посредник. Уменьшает степеньсвязанности взаимодействующих объектов - им не нужно хранитьссылки друг на друга.
http://www.slideshare.net/IgorShkulipa 62
Шаблоны поведенияПаттерн Memento получает и сохраняет за пределами объекта еговнутреннее состояние так, чтобы позже можно было восстановитьобъект в таком же состоянии.
Паттерн Observer определяет зависимость "один-ко-многим" междуобъектами так, что при изменении состояния одного объекта всезависящие от него объекты уведомляются и обновляютсяавтоматически.
Паттерн State позволяет объекту изменять свое поведение взависимости от внутреннего состояния. Создается впечатление, чтообъект изменил свой класс. Паттерн State является объектно-ориентированной реализацией конечного автомата.
Если поведение системы настраивается согласно одному из некоторогомножества алгоритму, то применение паттерна Strategy переноситсемейство алгоритмов в отдельную иерархию классов, что позволяетзаменять один алгоритм другим в ходе выполнения программы. Крометого, такую систему проще расширять и поддерживать.
Паттерн Template Method определяет основу алгоритма и позволяетподклассам изменить некоторые шаги этого алгоритма без измененияего общей структуры.
Паттерн Visitor определяет операцию, выполняемую на каждомэлементе из некоторой структуры без изменения классов этих объектов.
http://www.slideshare.net/IgorShkulipa 63
Паттерн Chain of Responsibility
Паттерн Chain of Responsibility позволяет избежать жесткойзависимости отправителя запроса от его получателя, при этомзапрос может быть обработан несколькими объектами.Объекты-получатели связываются в цепочку. Запроспередается по этой цепочке, пока не будет обработан.
Вводит конвейерную обработку для запроса с множествомвозможных обработчиков.
Объектно-ориентированный связанный список с рекурсивнымобходом.
http://www.slideshare.net/IgorShkulipa 64
Общая схема паттерна
Клиент
Обработчик 1
Обработчик 2
Обработчик 3
Обработчик ...
Обработчик n
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"; }
}
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; }
}
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();
} }
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;
}
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
http://www.slideshare.net/IgorShkulipa 70
Команда
Паттерн Command преобразовывает запрос на выполнениедействия в отдельный объект-команду. Такая инкапсуляцияпозволяет передавать эти действия другим функциям иобъектам в качестве параметра, приказывая им выполнитьзапрошенную операцию. Команда – это объект, поэтому надней допустимы любые операции, что и над объектом.
Команда используется, если:
–Система управляется событиями. При появлении такогособытия (запроса) необходимо выполнить определеннуюпоследовательность действий.
–Необходимо параметризировать объекты выполняемымдействием, ставить запросы в очередь или поддерживатьоперации отмены и повтора действий.
–Нужен объектно-ориентированный аналог функцииобратного вызова в процедурном программировании.
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();
}
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."); }
}
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();
}
}
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();
}
}
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();
}
}
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.
http://www.slideshare.net/IgorShkulipa 77
Паттерн Iterator
Назначение паттерна Iterator
• Предоставляет способ последовательного доступа ко всемэлементам составного объекта, не раскрывая его внутреннегопредставления.
• Абстракция в стандартных библиотеках C++ и Java, позволяющаяразделить классы коллекций и алгоритмов.
• Придает обходу коллекции "объектно-ориентированный статус".
• Полиморфный обход.
http://www.slideshare.net/IgorShkulipa 78
Интерфейсы
public interface IIterator
{
object Next();
object First();
bool Finished();
object Current();
}
public interface IIterCollection
{
IIterator GetIterator();
}
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;
}
}
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++);
}
}
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
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();
}
}
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
...
http://www.slideshare.net/IgorShkulipa 84
Паттерн Memento (Хранитель)
Назначение паттерна Memento:
• Не нарушая инкапсуляции, паттерн Memento получает и сохраняетза пределами объекта его внутреннее состояние так, чтобы позжеможно было восстановить объект в таком же состоянии.
• Является средством для инкапсуляции "контрольных точек"программы.
• Паттерн Memento придает операциям "Отмена" (undo) или "Откат"(rollback) статус "полноценного объекта".
Паттерн проектирования Memento определяет трех различныхучастников:
• Originator (хозяин) - объект, умеющий создавать хранителя, атакже знающий, как восстановить свое внутреннее состояние изхранителя.
• Caretaker (смотритель) - объект, который знает, почему и когдахозяин должен сохранять и восстанавливать себя.
• Memento (хранитель) - "ящик на замке", который пишется ичитается хозяином и за которым присматривает смотритель.
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);
}
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;
}
}
}
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);
}
}
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
http://www.slideshare.net/IgorShkulipa 89
Паттерн «Стратегия»
Паттерн Стратегия (Strategy) предназначен для определениясемейства алгоритмов и инкапсуляции каждого из них иобеспечения их взаимозаменяемости.
Переносит в отдельную иерархию классов все детали,связанные с реализацией алгоритмов.
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."); }
}
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();
}
}
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();
}
}
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.
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();
}
}
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.
http://www.slideshare.net/IgorShkulipa 96
Шаблон проектирования «Visitor»
Паттерн Visitor определяет операцию, выполняемую на каждомэлементе из некоторой структуры без изменения классов этихобъектов.
• Паттерн Visitor определяет операцию, выполняемую на каждомэлементе из некоторой структуры. Позволяет, не изменяя классыэтих объектов, добавлять в них новые операции.
Применение расширяющих методов значительно упрощает реализациюэтого паттерна.
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; }
}
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);
}
}
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
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.
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();
}
}
http://www.slideshare.net/IgorShkulipa 102
Некоторые архитектурные паттерны
http://www.slideshare.net/IgorShkulipa 103
MVC
Шаблон проектированияMVC разделяет работувеб-приложения на триотдельныефункциональные роли:
• модель данных(model)
• пользовательскийинтерфейс (view)
• управляющуюлогику (controller)
Таким образом, изменения,вносимые в один изкомпонентов, оказываютминимально возможноевоздействие на другиекомпоненты.
http://www.slideshare.net/IgorShkulipa 104
MVP
• Модель (model)представляет собой интерфейс,определяющий данные дляотображения или участвующие впользовательском интерфейсеиным образом
• Вид (view) - это интерфейс,который отображает данные(модель) и маршрутизируетпользовательские команды (илисобытия) Presenter-у, чтобы тотдействовал над этими данными.
• Presenter действует надмоделью и видом. Он извлекаетданные из хранилища (модели), иформатирует их для отображенияв Виде (view). Так же реализуетобработку событий вида.
http://www.slideshare.net/IgorShkulipa 106
Архитектурный паттерн MVVM
• Модель (Model), так же, как вклассическом паттерне MVC, Модельпредставляет собой фундаментальныеданные, необходимые для работыприложения (классы, структуры).
• Вид/Представление (View) также, как в классическом паттерне MVC,Вид — это графический интерфейс, тоесть окно, кнопки и.т.п.
• Модель вида (ViewModel, чтоозначает «Model of View») является содной стороны абстракцией Вида, а сдругой предоставляет обертку данныхиз Модели, которые подлежатсвязыванию. То есть она содержитМодель, которая преобразована кВиду, а так же содержит в себекоманды, которыми можетпользоваться Вид, чтобы влиять наМодель.