Warning: include(/cryptographp.fct.php): failed to open stream: No such file or directory in /backup/web_server/sites/softodon.com/www/article.php on line 5 Warning: include(): Failed opening '/cryptographp.fct.php' for inclusion (include_path='.:/usr/share/php:/usr/share/pear') in /backup/web_server/sites/softodon.com/www/article.php on line 5 Паттерны - основные понятия и базовые примеры паттернов
Меню в данный момент недоступно
Категории статей
Паттерны - основные понятия и базовые примеры паттернов

Примеры паттернов в этой статье будут базироваться на системном языке программирования C# (си шарп/c sharp).

Паттерны проектирования – это шаблоны в объектной реализации специфических поведенческих функций. То-есть, любое приложение, всегда может быть построено по известным уже методикам, алгоритмам, схемам... Те проблемы, которые встречаются в любом приложении решаются с помощью уже существующих подходов в организации объектной модели. Не важно, какое здание вы строите, вы всегда начнете с углубления котлована, потом – фундамент, затем стены и т.д. Причем, одно и то-же здание может быть выложено как с помощью красного кирпича, так и с помощью белого (силикатного). Вариантов – куча. Бесконечное количество. Но самые лучшие из них давным-давно завоевали признание и ими пользуются без особого раздумывания почему в данной ситуации применяется именно данный подход. Автомобиль также можно водить различным способом: можно включить первую передачу и проехать 100 км на ней. Но применяя паттерн вождения вы после небольшого разгона в нужный момент включите вторую, третью и т.д. Так вот, предопределенные действия и алгоритмы построения и манипулирования некоторой объектной модели как раз и называются шаблонами, то бишь – паттернами. Существует великое множество паттернов, и многие из них живут не во всех объектно-ориентированных языках поскольку каждый паттерн, так или иначе, связан с теми возможностями и недостатками объектно-ориентированного языка. Кроме того, многие паттерны не имеют единой трактовки. Каждый разработчик немного по-своему понимает тот или иной паттерн. Однако, всегда существует основной костяк паттерна от которого и отталкивается каждый программист при реализации его в приложении. Паттерн Factory Method (Фабрика) Factory Method (creational pattern) - это паттерн создания объектов. Данный шаблон проектирования предоставляет интерфейс (инструмент) для создания экземпляров некоторого класса. Казалось бы – какой может быть шаблон в создании экземпляров класса?! Но, минуточку внимания... При создании объекта наследники могут определить, какого же класса создавать экземпляр. «Фабрика» делегирует (предоставляет) создание объектов наследникам родительского (базового) класса. Это позволяет использовать в программе не конкретные классы, а манипулировать абстрактными объектами. Класс AbstractReader задаёт возможность чтения данных с некоторого источника данных (с любого источника): abstract class AbstractReader { public abstract void readData(Object input); } Данный класс могут наследовать другие классы. Экземпляр же этого класса создать нельзя. Для примера, создадим три класса; первый – для считывания данных с базы данных, второй – для считывания данных с текстового файла, третий – считывает двоичный код:

class ReaderDataBase : AbstractReader
{
public override void readData(Object input)
{
// некоторый код реализации
}
}
class ReaderTextFile : AbstractReader
{
public override void readData(Object input)
{
// некоторый код реализации
}
}
class ReaderBinaryFile : AbstractReader
{
public override void readData(Object input)
{
// некоторый код реализации
}
}
Для создания необходимого объекта код следующий: class FactoryMethod
{
public AbstractReader getCurrentReader(Object input)
{
AbstractReader someReader;
if (если input рассматривается формат табличных данных)
{
someReader = new ReaderDataBase();
}
if (если input рассматривается как текст)
{
someReader = new ReaderTextFile();
}
if (если input рассматривается как двоичные данные)
{
someReader = new ReaderBinaryFile();
}
return someReader;
}
}

Вместо базового абстрактного класса AbstractReader вполне пригодился бы интерфейс IAbstractReader. В таком случае, в наследуемых классах в определении метода readData(Object input) следует опустить модификатор override. В данном примере налицо столп объектно- ориентированного c# - полиморфизм в связке с наследованием. Шаблон Abstract Factory(Абстрактная Фабрика) Абстрактная фабрика (еще известный как kit) предоставляет механизм создания множества семейств объектов как одну логическую единицу без указания конкретных классов (типов). Но, объекты каждого семейства должны быть логически связаны между собой. Например, мы разрабатываем автопарк с его отделами. Оператор может отдавать команды на перемещение по автопарку и выезды на заказы: спортивных машин, автобусов, мотоциклов.

Интерфейсы машин:
public interface SportCar
{
void Rally();
}
public interface Bus
{
void Transportation();
}
public interface MotorBike
{
void Race();
}
Марка машин определенного отдела автопарка может быть любой, поэтому целесообразно применить абстрактную фабрику:
//создание гаража с машинами разных видов любой
//но одинаковой для данного отдела марки
public abstract class GarageFactory
{
public abstract SportCar createSportCar();
public abstract Bus createBus();
public abstract MotorBike createMotorBike();
}
Теперь мы можем создавать классы машин различных марок, соблюдая условие принадлежности разных типов машин в одном отделе к одной марке; помним, что тип машины задан соответствующим интерфейсом (представим, что под маркой «Жигули» выпускаются спортивные машины, автобусы и мотоциклы):
public class GygoolySportCar : SportCar
{
public void Rally()
{
// участие в спортивных гонках
}
}
public class GygoolyBus : Bus
{
public void Transportation()
{
// выезд на перевозку пассажиров
}
}
public class GygoolyMotorBike : MotorBike
{
public void Race()
{
// сдача в аренду байкерам
}
}
Только что мы создали определенную группу машин марки «Жигули». Так же мы можем создать группы машин других марок. Определим конкретную (не абстрактную) фабрику для «Жигулей»:
public class GygoolyGarageFactory : GarageFactory
{
public override SportCar createSportCar()
{
return new GygoolySportCar();
}
public override Bus createBus()
{
return new GygoolyBus();
}
public override MotorBike createMotorBike()
{
return new GygoolyMotorBike();
}
}
Создадим теперь конкретный отдел автомашин в автопарке. В данном классе нас не волнует, какой именно тип параметра мы передадим, то-есть какую конкретно фабрику, главное, что б члены этой фабрики имели типы вышеуказанных интерфейсов:
class Primer
{
static void Main()
{
...
}
public static void createSquadron (GarageFactory factory)
{
//в интерфейсные ссылки помещаются объекты соответствующих
//классов (при создании конвертируемые в тип
//соответствующего интерфейса)
SportCar SportCar = factory.createSportCar();
Bus Bus = factory.createBus();
MotorBike MotorBike = factory.createMotorBike();
}
}
Так мы создали отдел машин одной марки, то-есть объекты классов, которыми можно управлять одинаковым образом и с одной позиции. Конечно, абстрактная фабрика легко может быть интерфейсом. Так даже будет проще для реализации. Паттерн Singleton (Единственный) Данный шаблон применяют в случаях, когда необходимо создание только одного экземпляра некоторого класса. То- есть, когда в программе произойдет попытка создания ещё одного объекта некоего класса, то будет возвращён тот самый объект:
sealed class Singleton
{
private static Singleton _instance = new Singleton();
private Singleton() {} //закрытый конструктор
public static Singleton getInstance()
{
return _instance;
}
}
Конструктор класса помечен модификатором видимости private. Это не позволит создать экземпляр класса напрямую (используя оператор new). Модификатор sealed запечатывает класс – не может иметь наследников. Хотя sealed необязателен. Но некоторые будут сбиты с толку строкой кода private static Singleton _instance = new Singleton(); мол, каким образом сдесь возможно создание экземпляра данного класса, ведь конструктор помечен как закрытый. Объяснение очень простое: конструктор закрытый на уровне объекта, но внутри самого класса он видим в любом случае, а значит, работает внутри класса. Метод getInstance() всегда возвращает один единственный экземпляр класса Singleton. В многопоточных программах при одновременном вызове метода getInstance() из нескольких потоков можно создать несколько экземпляров класса Singleton. А должен остаться только один! Данная конструкция и не позволяет создавать экземпляры данного класса даже из других потоков. Проверить данный паттерн можно написав следующий код:
using System;
using System.Threading;
using System.Runtime.Remoting.Contexts;
class Primer
{
static void Main()
{
Singleton single = Singleton.getInstance();
single.flag = true;
Console.WriteLine("single.flag = " + single.flag);
Console.ReadLine();
Singleton single2 = Singleton.getInstance();
single2.flag = false;
Console.WriteLine("Выполнилась операция single2.flag =
false");
Console.ReadLine();
Console.WriteLine("А изменилось поле single.flag = " +
single.flag + " - один объект - две
ссылки");
Console.ReadLine();
}
}
class Singleton
{
private static Singleton _instance = new Singleton();
private Singleton() {} //закрытый конструктор
public static Singleton getInstance()
{
return _instance;
}
public bool flag;//любой член
}
Результат работы приложения:
Паттерн Adapter (Адаптер)
Шаблон адаптер применяется для того, что б объекты с различными интерфейсами понимали один-другого. «Адаптер» можно понимать как «переходник». Существует два основных вида адаптеров:
* Object Adapter;
* Class Adapter.
Object adapter представлен на следующей диаграмме. Клиенту для работы доступен интерфейс ITargetInterface. Данный интерфейс определяет шаблон метода (методов) для внутренней работы с некоторым классом, объектом. В данном случае – с объектом класса Adaptee. Клиент не знает о существовании указанного класса и, хотя реальная работа будет проводится с объектом именно этого класса, клиент будет уверен, что работает только с функциональностью интерфейса ITargetInterface. 
ObjectAdapter-структура
Код примера:
class ObjectAdapter : ITargetInterface
{
private Adaptee adaptee;
public ObjectAdapter(Adaptee adaptee)
{
this.adaptee = adaptee;
}
public void targetMethod()//вызов метода через целевой
интерфейсный метод
{
adaptee.method();
}
}
class Adaptee
{
public void method()
{
Console.WriteLine("Наш метод");
Console.ReadLine();
}
}
interface ITargetInterface
{
void targetMethod();
}
Преимущество такой реализации заключается в том, клиентский интерфейс напрочь отделён от адаптируемого интерфейса. Класс ClassAdapter наследуется от клиентского интерфейса и от Адаптируемого интерфейса (один из них может быть классом, как показано на рисунке): ClassAdapter-структура Возможная реализация класса
ClassAdapter:
class ClassAdapter : Adaptee, ITargetInterface
{
public void targetMethod()
{
method();
}
}
class Adaptee
{
protected void method()//закрыт на уровне объекта
{
Console.WriteLine("Наш метод");
Console.ReadLine();
}
}
interface ITargetInterface
{
void targetMethod();
}
Class Adapter внедрить проще, однако разделение клиента и адаптера здесь не такое выраженное как у Object Adapterа. Паттерн Memento (Память) Известен также как Token. Данный шаблон позволяет не нарушая инкапсуляции фиксировать и выносить за пределы объекта его внутреннее состояние, чтобы потом можно было восстановить состояние объекта в определенном моменте. Шаблон позволяет сохранять инкапсуляцию объекта, не позволяя напрямую изменять состояние объекта, а только через соответствующий интерфейс. С другой стороны, существует возможность возврата к предыдущему состоянию. Memento может понадобиться при создании preview для некоторой формы, при создании текстовых редакторов, графических и прочих приложений, где ведется история записи выполняемых пользователем операций. Проблема заключается в том, что хранить набор состояний объекта возможно во внешнем классе в виде списка типа ArrayList, в который динамически можно добавлять состояния множества объектов как одно общее состояние приложения в определенный момент. И при попытке возврата к этому состоянию можно вытягивать соответствующую запись из ArrayList-списка и переустанавливать состояния множества объектов, используя извлечённые данные. Однако в таком случае имеется вероятность, что не все связи между объектами данного приложения вернутся в требуемое состояние. Для решения этой проблемы и существует паттерн
Memento:
Memento-структура
using System;
class MainApp
{
static void Main()
{
Originator o = new Originator();
o.State = "On";
Caretaker c = new Caretaker();// Store internal state
c.Memento = o.CreateMemento();
o.State = "Off";// Continue changing originator
o.SetMemento(c.Memento);// Restore saved state
Console.ReadKey();// Wait for user
}
}
class Originator
{
private string _state;
public string State
{
get { return _state; }
set
{
_state = value;
Console.WriteLine("State = " + _state);
}
}
public Memento CreateMemento()// Creates memento
{
return (new Memento(_state));
}
public void SetMemento(Memento memento)// Restores
original state
{
Console.WriteLine("Restoring state...");
State = memento.State;
}
}
class Memento//хранит определенный вариант состояния
{
private string _state;//устанавливается однажды в момент
создания объекта
public Memento(string state)
{
this._state = state;
}
public string State
{
get { return _state;}
}
}
class Caretaker//создает новый вариант состояния, а также
извлекает необходимый вариант
{
private Memento _memento;
public Memento Memento
{
set { _memento = value;}
get { return _memento; }
}
}
Stratege
Шаблон стратегия очень часто применяется в компьютерных играх, но и не только. Очень удобен при созданни сущности, относящейся к определенной категории, при этом категория определяется набором некоторых интерфейсов, которые реализуются в данной категории. Реализовывается данный шаблон следующим образом. Создается набор интерфейсов, каждый из которых определяет некоторую модель поведения – метод (методы). Все вместе они полностью описывают существование всевозможных категорий.
Для создания некоторой категории создается класс, реализующий определенные из доступных интерфейсов.
Stratege-структура
Таким образом, можно создавать различные вариации соединений интерфейсов (моделей поведения). Если при очередном создании новой категории (класса) недостаёт необходимой функциональности, которая не определена ни одним из интерфейсов, легко создать новый интерфейс для задания недостающей модели и реализовать его в новом классе.
using System;
using System.Threading;
using System.Runtime.Remoting.Contexts;
class Primer
{
static void Main()
{
}
}
interface IRaceble
{
void race();
}
interface ICarrier
{
void carry();
}
interface ICar
{
void run();
}
interface ITruck
{
void transportation();
}
class LongVehicle : ICar, ITruck
{
public void run()
{
//some body
}
public void transportation()
{
//some body
}
}
class Taxy : ICar, ICarrier
{
public void run()
{
//some body
}
public void carry()
{
//some body
}
}
class RaceCar : ICar, IRaceble
{
public void run()
{
//some body
}
public void race()
{
//some body
}
}
class RentedCar : ICar, ICarrier
{
public void run()
{
//some body
}
public void carry()
{
//some body
}
}
class Toy : ICar
{
public void run()
{
//some body
}
}
MVC (Model-View-Controller)
Данный шаблон нельзя рассматривать как некоторую законченную модель. На сегодня существует великое множество вариаций данного паттерна. Скорее, MVC следует понимать не как отдельный паттерн, а как структурное взаимодействие целого набора всевозможных паттернов. Каких конкретно – решать каждому разработчику отдельно. Теоретически модельку MVC можно представить так, как показано на рисунке ниже. Главная задача сводится к созданию логической части программы – Model (модели), которая инкапсулирует в себе основную логику работы приложения. То-есть модель поведения. Называют также «Бизнес-слой», бизнес – внутренняя работа, которая не выносится наружу. Бизнес – есть бизнес. Модель никоем образом не должна знать о существовании контроллера и уровня представления. Тем более, что для модели возможно создать множество контроллеров и разных представлений. Однако, модель может получать от контроллера необходимые данные, получаемые у пользователя через клавиатуру и мышь например. Структурная схема MVC-шаблона В таком варианте модель не может содержать ссылок на контроллер или слой представления. Хотя, при острой необходимости данное правило можно нарушить. Уровень представления же управляется контроллером и получает необходимые данные из модели чаще всего в стиле get. Таким образом, отображение не может влиять на данные из модели, он может лишь считывать их для построения графики. Контроллер же способен порождать остальные уровни абстракции и, главное, взаимодействует с пользователем. Паттерн MVC достаточно разнообразен и слишком абстрактен для того, что бы его можно было наглядно описать некоторым кодом. Этот шаблон, как я уже сказал, вначале некоторое логическое построения вашего приложения, а уже потом – реализация в коде программы. Главное понимать, что и модель, и контроллер, и представление – это всего-навсего конкретный класс (несколько классов) и взаимодействие между ними должно соответствовать логическим связям, показанным на рисунке. Все вышеперечисленные шаблоны сильно упрощены для ясного их понимания. Каждый из них можно и нужно сильно конкретизировать и, при необходимости расширять, и настраивать под конкретное задание.
КатегорияСистемная и прикладная разработка
РазделСредства разработки
Просмотров2817
Дата добавления2012-05-18 02:07:28
Очков18
Проголосовавших5
Средний балл3
Автор0



Рейтинг: 3 из 5 (голосов: 5)

Написать отзыв к статье


Fatal error: Call to undefined function dsp_crypt() in /backup/web_server/sites/softodon.com/www/article.php on line 110