3. http://www.slideshare.net/IgorShkulipa 3
SOLID. Принципы проектирования классов
SOLID – это акроним названий пяти основных принципов
проектирования классов, сформулированных Робертом Мартином:
•Single responsibility (принцип одной ответственности),
•Open for extension and closed for modification (принцип
открытости/закрытости, или открытость для расширения и
закрытость для модификации),
•Liskov substitution (принцип подстановки Лисков),
•Interface segregation (принцип разделения интерфейса),
•Dependency inversion (принцип инверсии зависимостей).
4. http://www.slideshare.net/IgorShkulipa 4
Single Responsibility
Принцип единственной ответственности (Single Responsibility Principle)
часто определяют так: у объекта должна быть только одна причина для
изменения; чем больше файл или класс, тем труднее достичь этой
цели.
Этот принцип говорит о том, что по-хорошему каждый класс должен
решать только одну задачу. Это совсем не значит, что в классе
должен быть всего один метод. Это означает, что методы класса
должны быть связаны одной общей целью.
5. 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) { }
}
6. http://www.slideshare.net/IgorShkulipa 6
Open for Extension and Closed for Modification
Объекты проектирования (классы, функции, модули и т.д.) должны быть
открыты для расширения, но закрыты для модификации.
Этот принцип говорит о том, что классы нужно проектировать так, чтобы
впоследствии иметь возможность изменять поведение класса, не
изменяя его код.
7. 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) { }
}
11. 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() { }
}
12. http://www.slideshare.net/IgorShkulipa 12
Dependency Inversion
• Модули верхних уровней не должны зависеть от модулей нижних
уровней.
• Оба типа модулей должны зависеть от абстракций.
• Абстракции не должны зависеть от деталей.
• Детали должны зависеть от абстракций.
13. 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();
}
}
15. http://www.slideshare.net/IgorShkulipa 15
Паттерны (шаблоны проектирования)
Паттерн описывает задачу, которая снова и снова возникает в работе, а так же
принцип ее решения, причем таким образом, что это решение можно потом
использовать много раз, ничего не изобретая заново.
В общем случае паттерн состоит из четырех основных элементов:
Имя. Присваивание паттернам имен позволяет проектировать на более высоком
уровне абстракции. С помощью имен паттернов можно вести общение с
коллегами. Назначение паттернам имен упрощает общение в профессиональной
среде.
Задача - это описание того, когда следует применять паттерн. Необходимо
сформулировать задачу и ее контекст. Может описываться конкретная проблема
проектирования, например способ представления алгоритмов в виде объектов.
Так же задача может включать перечень условий, при выполнении которых имеет
смысл применять данный паттерн.
Решение представляет собой описание элементов дизайна, отношений между
ними, функций каждого элемента. Конкретный дизайн или реализация не имеются
ввиду, поскольку паттерн – это шаблон, применимый в самых разных ситуациях.
Результаты - это следствия применения паттерна и разного рода компромиссы.
Хотя при описании проектных решений о последствиях часто не упоминают, знать
о них необходимо, чтобы можно было выбрать между различными вариантами и
оценить преимущества и недостатки данного паттерна.
16. http://www.slideshare.net/IgorShkulipa 16
Паттерны (шаблоны проектирования)
Паттерн описывает задачу, которая снова и снова возникает в работе, а так же
принцип ее решения, причем таким образом, что это решение можно потом
использовать много раз, ничего не изобретая заново.
В общем случае паттерн состоит из четырех основных элементов:
Имя. Присваивание паттернам имен позволяет проектировать на более высоком
уровне абстракции. С помощью имен паттернов можно вести общение с
коллегами. Назначение паттернам имен упрощает общение в профессиональной
среде.
Задача - это описание того, когда следует применять паттерн. Необходимо
сформулировать задачу и ее контекст. Может описываться конкретная проблема
проектирования, например способ представления алгоритмов в виде объектов.
Так же задача может включать перечень условий, при выполнении которых имеет
смысл применять данный паттерн.
Решение представляет собой описание элементов дизайна, отношений между
ними, функций каждого элемента. Конкретный дизайн или реализация не имеются
ввиду, поскольку паттерн – это шаблон, применимый в самых разных ситуациях.
Результаты - это следствия применения паттерна и разного рода компромиссы.
Хотя при описании проектных решений о последствиях часто не упоминают, знать
о них необходимо, чтобы можно было выбрать между различными вариантами и
оценить преимущества и недостатки данного паттерна.
17. http://www.slideshare.net/IgorShkulipa 17
Классификация паттернов
Паттерны проектирования программных систем делятся на
следующие категории:
Архитектурные паттерны. Описывают структурную схему
программной системы в целом. В данной схеме указываются
отдельные функциональные составляющие системы,
называемые подсистемами, а также взаимоотношения между
ними.
Паттерны проектирования. описывают схемы детализации
программных подсистем и отношений между ними, при этом они
не влияют на структуру программной системы в целом и
сохраняют независимость от реализации языка
программирования.
Идиомы - низкоуровневые паттерны, имеют дело с вопросами
реализации какой-либо проблемы с учетом особенностей
данного языка программирования.
18. http://www.slideshare.net/IgorShkulipa 18
Паттерны проектирования
Паттерны проектирования делятся на следующие категории:
Порождающие - шаблоны проектирования, которые
абстрагируют процесс создания объектов. Они позволяют
сделать систему независимой от способа создания, композиции
и представления объектов.
Структурные - шаблоны проектирования, в которых
рассматривается вопрос о том, как из классов и объектов
образуются более крупные структуры.
Поведенческие - шаблоны проектирования, определяющие
алгоритмы и способы реализации взаимодействия различных
объектов и классов.
19. http://www.slideshare.net/IgorShkulipa 19
Порождающие паттерны
• Singleton (Одиночка) - контролирует создание единственного
экземпляра некоторого класса и предоставляет доступ к нему.
• Factory Method (Фабричный метод) - В его классическом варианте
вводится полиморфный класс Factory, в котором определяется
интерфейс фабричного метода, а ответственность за создание объектов
конкретных классов переносится на производные от Factory классы, в
которых этот метод переопределяется.
• Abstract Factory (Абстрактная фабрика) - использует несколько
фабричных методов и предназначен для создания целого семейства или
группы взаимосвязанных объектов.
• Builder (Строитель) - определяет процесс поэтапного конструирования
сложного объекта, в результате которого могут получаться разные
представления этого объекта.
• Prototype (Прототип) - создает новые объекты с помощью прототипов.
Прототип - некоторый объект, умеющий создавать по запросу копию
самого себя.
• Object Pool (Пул объектов) - используется в случае, когда создание
объекта требует больших затрат или может быть создано только
ограниченное количество объектов некоторого класса.
20. 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();
}
}
21. http://www.slideshare.net/IgorShkulipa 21
Применение Singleton
Применяется, когда нужен только один экземпляр класса.
Например для хранения глобальной конфигурации системы,
для ведения логов, связи с базой данных и т.д.
Основное преимущество перед глобальными переменными в
том, что экземпляр класса создается не при инициализации
программы, а по первому требованию.
22. http://www.slideshare.net/IgorShkulipa 22
Factory Method
Паттерн Factory Method может быть полезным в решении
следующих задач:
1. Система должна оставаться расширяемой путем добавления
объектов новых типов. Непосредственное использование
оператора new является нежелательным, так как в этом
случае код создания объектов с указанием конкретных типов
может получиться разбросанным по всему приложению. Тогда
такие операции как добавление в систему объектов новых
типов или замена объектов одного типа на другой будут
затруднительными. Паттерн Factory Method позволяет системе
оставаться независимой как от самого процесса порождения
объектов, так и от их типов.
2. Заранее известно, когда нужно создавать объект, но
неизвестен его тип.
23. http://www.slideshare.net/IgorShkulipa 23
Описание паттерна Factory Method
Для того, чтобы система оставалась независимой от различных типов
объектов, паттерн Factory Method использует механизм полиморфизма -
классы всех конечных типов наследуются от одного абстрактного
базового класса, предназначенного для полиморфного использования. В
этом базовом классе определяется единый интерфейс, через который
пользователь будет оперировать объектами конечных типов.
Для обеспечения относительно простого добавления в систему новых типов
паттерн Factory Method локализует создание объектов конкретных типов в
специальном классе-фабрике. Методы этого класса, посредством которых
создаются объекты конкретных классов, называются фабричными.
Существуют две разновидности паттерна Factory Method:
Обобщенный конструктор, когда в том же самом полиморфном базовом
классе, от которого наследуются производные классы всех создаваемых в
системе типов, определяется статический фабричный метод. В качестве
параметра в этот метод должен передаваться идентификатор типа
создаваемого объекта.
Классический вариант фабричного метода, когда интерфейс фабричных
методов объявляется в независимом классе-фабрике, а их реализация
определяется конкретными подклассами этого класса.
24. 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";
}
}
25. 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();
}
}
26. 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
27. http://www.slideshare.net/IgorShkulipa 27
Преимущества и недостатки
Преимущества паттерна Factory Method:
–Создает объекты разных типов, позволяя системе оставаться
независимой как от самого процесса создания, так и от типов
создаваемых объектов.
Недостатки паттерна Factory Method:
–В случае классического варианта паттерна даже для
порождения единственного объекта необходимо создавать
соответствующую фабрику
28. http://www.slideshare.net/IgorShkulipa 28
Abstract Factory
Паттерн Abstract Factory стоит использовать, когда:
–Система должна оставаться независимой как от процесса
создания новых объектов, так и от типов порождаемых
объектов. Непосредственное использование оператора new в
коде приложения нежелательно.
–Необходимо создавать группы или семейства
взаимосвязанных объектов, исключая возможность
одновременного использования объектов из разных семейств
в одном контексте.
29. 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";
}
}
30. 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";
}
}
31. 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();
}
}
32. 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
33. http://www.slideshare.net/IgorShkulipa 33
Паттерн «Прототип»
Использует для создания новых объектов копию самого себя.
Паттерн Prototype (прототип) можно использовать в следующих
случаях:
–Система должна оставаться независимой как от процесса
создания новых объектов, так и от типов порождаемых
объектов. Непосредственное использование оператора new в
коде приложения считается нежелательным.
–Необходимо создавать объекты, точные классы которых
становятся известными уже на стадии выполнения
программы.
34. http://www.slideshare.net/IgorShkulipa 34
Интерфейс ICloneable
Поддерживает копирование, при котором создается новый экземпляр
класса с тем же значением, что и у существующего экземпляра.
Метод Clone() создает новый объект, являющийся копией текущего
экземпляра.
Метод MemberwiseClone для создания неполной копии создает новый
объект, а затем копирует в него нестатические поля текущего объекта.
Если поле относится к типу значения, выполняется побитовое
копирование полей. Если поле относится к ссылочному типу,
копируются ссылки, а не объекты, на которые они указывают;
следовательно, ссылки в исходном объекте и его клоне указывают на
один и тот же объект.
35. 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; ;
}
}
37. http://www.slideshare.net/IgorShkulipa 37
Паттерн Builder
Паттерн Builder может помочь в решении следующих задач:
–В системе могут существовать сложные объекты, создание
которых за одну операцию затруднительно или невозможно.
Требуется поэтапное построение объектов с контролем
результатов выполнения каждого этапа.
–Данные должны иметь несколько представлений. Например,
если есть некоторый исходный документ в формате RTF (Rich
Text Format), в общем случае содержащий текст,
графические изображения и служебную информацию о
форматировании (размер и тип шрифтов, отступы и др.).
Если этот документ в формате RTF преобразовать в другие
форматы (например, Microsoft Word или простой ASCII-текст),
то полученные документы и будут представлениями
исходных данных.
38. http://www.slideshare.net/IgorShkulipa 38
Описание паттерна Builder
Паттерн Builder отделяет алгоритм поэтапного конструирования
сложного объекта от его внешнего представления так, что с
помощью одного и того же алгоритма можно получать разные
представления этого объекта.
Для этого паттерн Builder определяет алгоритм поэтапного
создания продукта в специальном классе Director
(распорядитель), а ответственность за координацию процесса
сборки отдельных частей продукта возлагает на иерархию
классов Builder. В этой иерархии базовый класс Builder
объявляет интерфейс для построения отдельных частей
продукта, а соответствующие подклассы конкретных
строителей их реализуют подходящим образом, например,
создают или получают нужные ресурсы, сохраняют
промежуточные результаты, контролируют результаты
выполнения операций.
39. 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);
}
}
42. 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
43. http://www.slideshare.net/IgorShkulipa 43
StringBuilder
Предоставляет изменяемую строку символов.
[SerializableAttribute]
[ComVisibleAttribute(true)]
public sealed class StringBuilder : ISerializable
Операция объединения объекта String всегда создает новый объект из
существующей строки и новых данных. Объект StringBuilder
поддерживает буфер для размещения и конкатенации новых данных.
Новые данные добавляются в имеющийся буфер только в том случае,
если в нем имеется достаточное свободное пространство для их
размещения, в противном случае выделяется новый буфер
достаточного размера, данные из оригинального буфера копируются в
другой буфер, и новые данные добавляются уже в новый буфер.
45. http://www.slideshare.net/IgorShkulipa 45
Object Pool
Применение паттерна Object Pool может значительно повысить
производительность системы; его использование наиболее
эффективно в ситуациях, когда создание экземпляров
некоторого класса требует больших затрат, объекты в системе
создаются часто, но число создаваемых объектов в единицу
времени ограничено.
Пулы объектов (известны также как пулы ресурсов)
используются для управления кэшированием объектов. Клиент,
имеющий доступ к пулу объектов может избежать создания
новых объектов, просто запрашивая в пуле уже созданный
экземпляр. Пул объектов может быть растущим, когда при
отсутствии свободных создаются новые объекты или c
ограничением количества создаваемых объектов.
46. 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";
}
}
47. 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;
}
}
}...
48. 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;
}
49. http://www.slideshare.net/IgorShkulipa 49
Использование Object Pool
class 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();
}
}
51. http://www.slideshare.net/IgorShkulipa 51
Структурные шаблоны проектирования
–Adapter представляет собой программную обертку над уже
существующими классами и предназначен для преобразования их
интерфейсов к виду, пригодному для последующего использования в
новом программном проекте.
–Bridge отделяет абстракцию от реализации так, что то и другое
можно изменять независимо.
–Composite группирует схожие объекты в древовидные структуры.
Рассматривает единообразно простые и сложные объекты.
–Decorator используется для расширения функциональности
объектов. Являясь гибкой альтернативой порождению классов,
паттерн Decorator динамически добавляет объекту новые
обязанности.
–Facade предоставляет высокоуровневый унифицированный
интерфейс к набору интерфейсов некоторой подсистемы, что
облегчает ее использование.
–Flyweight использует разделение для эффективной поддержки
множества объектов.
–Proxy замещает другой объект для контроля доступа к нему.
52. http://www.slideshare.net/IgorShkulipa 52
Адаптер
Паттерн Adapter, представляет собой программную обертку над
существующими классами, преобразуя их интерфейсы к виду,
пригодному для последующего использования.
Пусть класс, интерфейс которого нужно адаптировать к нужному
виду, имеет имя Adaptee. Для решения задачи преобразования
его интерфейса паттерн Adapter вводит следующую иерархию
классов:
–Виртуальный базовый класс Target. Здесь объявляется
пользовательский интерфейс подходящего вида. Только этот
интерфейс доступен для пользователя.
–Производный класс Adapter, реализующий интерфейс Target.
В этом классе также имеется указатель или ссылка на
экземпляр Adaptee. Паттерн Adapter использует этот
указатель для перенаправления клиентских вызовов в
Adaptee. Так как интерфейсы Adaptee и Target несовместимы
между собой, то эти вызовы обычно требуют
преобразования.
53. 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();
}
}
54. 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);
}
}
55. 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);
}
}
56. 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
60. 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
61. http://www.slideshare.net/IgorShkulipa 61
Шаблоны поведения
Паттерн Chain of Responsibility позволяет обработать запрос
нескольким объектам-получателям. Получатели связываются в цепочку,
и запрос передается по цепочке, пока не будет обработан каким-то
объектом. Паттерн Chain of Responsibility позволяет также избежать
жесткой зависимости между отправителем запроса и его получателями.
Паттерн Command преобразовывает запрос на выполнение действия в
отдельный объект-команду. Это придает системе гибкость: позволяет
осуществлять динамическую замену команд, использовать сложные
составные команды, осуществлять отмену операций.
Паттерн Iterator предоставляет механизм обхода элементов составных
объектов (коллекций) не раскрывая их внутреннего представления.
Паттерн Interpreter предназначен для решения повторяющихся задач,
которые можно описать некоторым языком. Для этого паттерн
Interpreter описывает решаемую задачу в виде предложений этого
языка, а затем интерпретирует их.
Паттерн Mediator инкапсулирует взаимодействие совокупности
объектов в отдельный объект-посредник. Уменьшает степень
связанности взаимодействующих объектов - им не нужно хранить
ссылки друг на друга.
62. http://www.slideshare.net/IgorShkulipa 62
Шаблоны поведения
Паттерн Memento получает и сохраняет за пределами объекта его
внутреннее состояние так, чтобы позже можно было восстановить
объект в таком же состоянии.
Паттерн Observer определяет зависимость "один-ко-многим" между
объектами так, что при изменении состояния одного объекта все
зависящие от него объекты уведомляются и обновляются
автоматически.
Паттерн State позволяет объекту изменять свое поведение в
зависимости от внутреннего состояния. Создается впечатление, что
объект изменил свой класс. Паттерн State является объектно-
ориентированной реализацией конечного автомата.
Если поведение системы настраивается согласно одному из некоторого
множества алгоритму, то применение паттерна Strategy переносит
семейство алгоритмов в отдельную иерархию классов, что позволяет
заменять один алгоритм другим в ходе выполнения программы. Кроме
того, такую систему проще расширять и поддерживать.
Паттерн Template Method определяет основу алгоритма и позволяет
подклассам изменить некоторые шаги этого алгоритма без изменения
его общей структуры.
Паттерн Visitor определяет операцию, выполняемую на каждом
элементе из некоторой структуры без изменения классов этих объектов.
63. http://www.slideshare.net/IgorShkulipa 63
Паттерн Chain of Responsibility
Паттерн Chain of Responsibility позволяет избежать жесткой
зависимости отправителя запроса от его получателя, при этом
запрос может быть обработан несколькими объектами.
Объекты-получатели связываются в цепочку. Запрос
передается по этой цепочке, пока не будет обработан.
Вводит конвейерную обработку для запроса с множеством
возможных обработчиков.
Объектно-ориентированный связанный список с рекурсивным
обходом.
65. 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"; }
}
66. 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; }
}
67. 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();
} }
68. 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;
}
69. 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
70. http://www.slideshare.net/IgorShkulipa 70
Команда
Паттерн Command преобразовывает запрос на выполнение
действия в отдельный объект-команду. Такая инкапсуляция
позволяет передавать эти действия другим функциям и
объектам в качестве параметра, приказывая им выполнить
запрошенную операцию. Команда – это объект, поэтому над
ней допустимы любые операции, что и над объектом.
Команда используется, если:
–Система управляется событиями. При появлении такого
события (запроса) необходимо выполнить определенную
последовательность действий.
–Необходимо параметризировать объекты выполняемым
действием, ставить запросы в очередь или поддерживать
операции отмены и повтора действий.
–Нужен объектно-ориентированный аналог функции
обратного вызова в процедурном программировании.
73. 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();
}
}
74. 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();
}
}
75. 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();
}
}
76. 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.
77. http://www.slideshare.net/IgorShkulipa 77
Паттерн Iterator
Назначение паттерна Iterator
• Предоставляет способ последовательного доступа ко всем
элементам составного объекта, не раскрывая его внутреннего
представления.
• Абстракция в стандартных библиотеках C++ и Java, позволяющая
разделить классы коллекций и алгоритмов.
• Придает обходу коллекции "объектно-ориентированный статус".
• Полиморфный обход.
79. 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;
}
}
84. http://www.slideshare.net/IgorShkulipa 84
Паттерн Memento (Хранитель)
Назначение паттерна Memento:
• Не нарушая инкапсуляции, паттерн Memento получает и сохраняет
за пределами объекта его внутреннее состояние так, чтобы позже
можно было восстановить объект в таком же состоянии.
• Является средством для инкапсуляции "контрольных точек"
программы.
• Паттерн Memento придает операциям "Отмена" (undo) или "Откат"
(rollback) статус "полноценного объекта".
Паттерн проектирования Memento определяет трех различных
участников:
• Originator (хозяин) - объект, умеющий создавать хранителя, а
также знающий, как восстановить свое внутреннее состояние из
хранителя.
• Caretaker (смотритель) - объект, который знает, почему и когда
хозяин должен сохранять и восстанавливать себя.
• Memento (хранитель) - "ящик на замке", который пишется и
читается хозяином и за которым присматривает смотритель.
85. 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);
}
86. 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;
}
}
}
87. 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);
}
}
88. 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
89. http://www.slideshare.net/IgorShkulipa 89
Паттерн «Стратегия»
Паттерн Стратегия (Strategy) предназначен для определения
семейства алгоритмов и инкапсуляции каждого из них и
обеспечения их взаимозаменяемости.
Переносит в отдельную иерархию классов все детали,
связанные с реализацией алгоритмов.
91. 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();
}
}
92. 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();
}
}
93. 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.
94. 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();
}
}
95. 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.
96. http://www.slideshare.net/IgorShkulipa 96
Шаблон проектирования «Visitor»
Паттерн Visitor определяет операцию, выполняемую на каждом
элементе из некоторой структуры без изменения классов этих
объектов.
• Паттерн Visitor определяет операцию, выполняемую на каждом
элементе из некоторой структуры. Позволяет, не изменяя классы
этих объектов, добавлять в них новые операции.
Применение расширяющих методов значительно упрощает реализацию
этого паттерна.
97. 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; }
}
98. 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);
}
}
100. 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.
101. 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();
}
}
103. http://www.slideshare.net/IgorShkulipa 103
MVC
Шаблон проектирования
MVC разделяет работу
веб-приложения на три
отдельные
функциональные роли:
• модель данных
(model)
• пользовательский
интерфейс (view)
• управляющую
логику (controller)
Таким образом, изменения,
вносимые в один из
компонентов, оказывают
минимально возможное
воздействие на другие
компоненты.
104. http://www.slideshare.net/IgorShkulipa 104
MVP
• Модель (model)
представляет собой интерфейс,
определяющий данные для
отображения или участвующие в
пользовательском интерфейсе
иным образом
• Вид (view) - это интерфейс,
который отображает данные
(модель) и маршрутизирует
пользовательские команды (или
события) Presenter-у, чтобы тот
действовал над этими данными.
• Presenter действует над
моделью и видом. Он извлекает
данные из хранилища (модели), и
форматирует их для отображения
в Виде (view). Так же реализует
обработку событий вида.
106. http://www.slideshare.net/IgorShkulipa 106
Архитектурный паттерн MVVM
• Модель (Model), так же, как в
классическом паттерне MVC, Модель
представляет собой фундаментальные
данные, необходимые для работы
приложения (классы, структуры).
• Вид/Представление (View) так
же, как в классическом паттерне MVC,
Вид — это графический интерфейс, то
есть окно, кнопки и.т.п.
• Модель вида (ViewModel, что
означает «Model of View») является с
одной стороны абстракцией Вида, а с
другой предоставляет обертку данных
из Модели, которые подлежат
связыванию. То есть она содержит
Модель, которая преобразована к
Виду, а так же содержит в себе
команды, которыми может
пользоваться Вид, чтобы влиять на
Модель.