Главная страница
Навигация по странице:

  • Когда надо использовать Адаптер

  • Формальное описание адаптера объектов на C выглядит таким образом

  • 21. Шаблон проектирования Прокси (Proxy). Назначение. Пример использования.

  • 22. Шаблон проектирования Декоратор (Decorator). Назначение. Пример использования.

  • Даб работа по методам программирования. обновлено пронько. 1. Классы в C#. Модификаторы доступа. Поля, свойства, индексаторы


    Скачать 0.78 Mb.
    Название1. Классы в C#. Модификаторы доступа. Поля, свойства, индексаторы
    АнкорДаб работа по методам программирования
    Дата11.03.2023
    Размер0.78 Mb.
    Формат файлаdocx
    Имя файлаобновлено пронько.docx
    ТипДокументы
    #980160
    страница5 из 6
    1   2   3   4   5   6

    20. Шаблон проектирования Адаптер (Adapter). Назначение. Пример использования.

    Паттерн Адаптер (Adapter) предназначен для преобразования интерфейса одного класса в интерфейс другого. Благодаря реализации данного паттерна мы можем использовать вместе классы с несовместимыми интерфейсами.

    Когда надо использовать Адаптер?

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

    • Когда надо использовать уже существующий класс совместно с другими классами, интерфейсы которых не совместимы

    Формальное определение паттерна на UML выглядит следующим образом:



    Формальное описание адаптера объектов на C# выглядит таким образом:

    class Client

    {

        public void Request(Target target)

        {

            target.Request();

        }

    }

    // класс, к которому надо адаптировать другой класс  

    class Target

    {

        public virtual void Request()

        {}

    }

     

    // Адаптер

    class Adapter : Target

    {

        private Adaptee adaptee = new Adaptee();

     

        public override void Request()

        {

            adaptee.SpecificRequest();

        }

    }

     

    // Адаптируемый класс

    class Adaptee

    {

        public void SpecificRequest()

        {}

    }

    Участники

    • Target: представляет объекты, которые используются клиентом

    • Client: использует объекты Target для реализации своих задач

    • Adaptee: представляет адаптируемый класс, который мы хотели бы использовать у клиента вместо объектов Target

    • Adapter: собственно адаптер, который позволяет работать с объектами Adaptee как с объектами Target.

    То есть клиент ничего не знает об Adaptee, он знает и использует только объекты Target. И благодаря адаптеру мы можем на клиенте использовать объекты Adaptee как Target

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

    class Program

    {

        static void Main(string[] args)

        {

            // путешественник

            Driver driver = new Driver();

            // машина

            Auto auto = new Auto();

            // отправляемся в путешествие

            driver.Travel(auto);

            // встретились пески, надо использовать верблюда

            Camel camel = new Camel();

            // используем адаптер

            ITransport camelTransport = new CamelToTransportAdapter(camel);

            // продолжаем путь по пескам пустыни

            driver.Travel(camelTransport);

     

            Console.Read();

        }

    }

    interface ITransport

    {

        void Drive();

    }

    // класс машины

    class Auto : ITransport

    {

        public void Drive()

        {

            Console.WriteLine("Машина едет по дороге");

        }

    }

    class Driver

    {

        public void Travel(ITransport transport)

        {

            transport.Drive();

        }

    }

    // интерфейс животного

    interface IAnimal

    {

        void Move();

    }

    // класс верблюда

    class Camel : IAnimal

    {

        public void Move()

        {

            Console.WriteLine("Верблюд идет по пескам пустыни");

        }

    }

    // Адаптер от Camel к ITransport

    class CamelToTransportAdapter : ITransport

    {

        Camel camel;

        public CamelToTransportAdapter(Camel c)

        {

            camel = c;

        }

     

        public void Drive()

        {

            camel.Move();

        }

    }

    И консоль выведет:

    Машина едет по дороге

    Верблюд идет по пескам пустыни

    В данном случае в качестве клиента применяется класс Driver, который использует объект ITransport. Адаптируемым является класс верблюда Camel, который нужно использовать в качестве объекта ITransport. И адптером служит класс CamelToTransportAdapter.

    Возможно, кому-то покажется надуманной проблема использования адаптеров особенно в данном случае, так как мы могли бы применить интерфейс ITransport к классу Camel и реализовать его метод Drive(). Однако, в данном случае может случиться дублирование функциональностей: интерфейс IAnimal имеет метод Move(), реализация которого в классе верблюда могла бы быть похожей на реализацию метода Drive() из интерфейса ITransport. Кроме того, нередко бывает, что классы спроектированы кем-то другим, и мы никак не можем на них повлиять. Мы только используем их. В результате чего адаптеры довольно широко распространены в .NET. В частности, многочисленные встроенные классы, которые используются для подключения к различным системам баз данных, как раз и реализуют паттерн адаптер (например, класс System.Data.SqlClient.SqlDataAdapter).

    21. Шаблон проектирования Прокси (Proxy). Назначение. Пример использования.

    Паттерн Заместитель (Proxy) предоставляет объект-заместитель, который управляет доступом к другому объекту. То есть создается объект-суррогат, который может выступать в роли другого объекта и замещать его.

    Назначение:

    1. Когда надо осуществлять взаимодействие по сети, а объект-проси должен имитировать поведения объекта в другом адресном пространстве. Использование прокси позволяет снизить накладные издержки при передаче данных через сеть. Подобная ситуация еще называется удалённый заместитель (remote proxies).

    2. Когда нужно управлять доступом к ресурсу, создание которого требует больших затрат. Реальный объект создается только тогда, когда он действительно может понадобится, а до этого все запросы к нему обрабатывает прокси-объект. Подобная ситуация еще называется виртуальный заместитель (virtual proxies).

    3. Когда необходимо разграничить доступ к вызываемому объекту в зависимости от прав вызывающего объекта. Подобная ситуация еще называется защищающий заместитель (protection proxies).

    4. Когда нужно вести подсчет ссылок на объект или обеспечить потокобезопасную работу с реальным объектом. Подобная ситуация называется "умные ссылки" (smart reference).

    С помощью UML паттерн может быть описан так:



    Примериспользования:

    1. class Client

    2. {

    3. void Main()

    4. {

    5. Subject subject = new Proxy();

    6. subject.Request();

    7. }

    8. }

    9. abstract class Subject

    10. {

    11. public abstract void Request();

    12. }

    13.

    14. class RealSubject : Subject

    15. {

    16. public override void Request()

    17. {}

    18. }

    19. class Proxy : Subject

    20. {

    21. RealSubject realSubject;

    22. public override void Request()

    23. {

    24. if (realSubject == null)

    25. realSubject = new RealSubject();

    26. realSubject.Request();

    27. }

    28. }

    Участники паттерна:

    1. Subject: определяет общий интерфейс для Proxy и RealSubject. Поэтому Proxy может использоваться вместо RealSubject.

    2. RealSubject: представляет реальный объект, для которого создается прокси.

    3. Proxy: заместитель реального объекта. Хранит ссылку на реальный объект, контролирует к нему доступ, может управлять его созданием и удалением. При необходимости Proxy переадресует запросы объекту RealSubject.

    4. Client: использует объект Proxy для доступа к объекту RealSubject.

    22. Шаблон проектирования Декоратор (Decorator). Назначение. Пример использования.

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

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

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

    Схематически шаблон "Декоратор" можно выразить следующим образом:



    abstract class Component

    {

        public abstract void Operation();

    }

    class ConcreteComponent : Component

    {

        public override void Operation()

        {}

    }

    abstract class Decorator : Component

    {

        protected Component component;

     

        public void SetComponent(Component component)

        {

            this.component = component;

        }

     

        public override void Operation()

        {

            if (component != null)

                component.Operation();

        }

    }

    class ConcreteDecoratorA : Decorator

    {

        public override void Operation()

        {

            base.Operation();

        }

    }

    class ConcreteDecoratorB : Decorator

    {

        public override void Operation()

        {

            base.Operation();

        }

    }

    Участники

    • Component: абстрактный класс, который определяет интерфейс для наследуемых объектов

    • ConcreteComponent: конкретная реализация компонента, в которую с помощью декоратора добавляется новая функциональность

    • Decorator: собственно декоратор, реализуется в виде абстрактного класса и имеет тот же базовый класс, что и декорируемые объекты. Поэтому базовый класс Component должен быть по возможности легким и определять только базовый интерфейс.

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

    Классы ConcreteDecoratorA и ConcreteDecoratorB представляют дополнительные функциональности, которыми должен быть расширен объект ConcreteComponent.

    Рассмотрим пример. Допустим, у нас есть пиццерия, которая готовит различные типы пицц с различными добавками. Есть итальянская, болгарская пиццы. К ним могут добавляться помидоры, сыр и т.д. И в зависимости от типа пицц и комбинаций добавок пицца может иметь разную стоимость. Теперь посмотрим, как это изобразить в программе на C#:

    class Program

    {

        static void Main(string[] args)

        {

            Pizza pizza1 = new ItalianPizza();

            pizza1 = new TomatoPizza(pizza1); // итальянская пицца с томатами

     

            Pizza pizza3 = new BulgerianPizza();

            pizza3 = new TomatoPizza(pizza3);

            pizza3 = new CheesePizza(pizza3);// болгарская пиццы с томатами и сыром

     

            Console.ReadLine();

        }

    }

    abstract class Pizza

    {

        public Pizza(string n)

        {

            this.Name = n;

        }

        public string Name {get; protected set;}

        public abstract int GetCost();

    }

    class ItalianPizza : Pizza

    {

        public ItalianPizza() : base("Итальянская пицца")

        { }

        public override int GetCost()

        {

            return 10;

        }

    }

    class BulgerianPizza : Pizza

    {

        public BulgerianPizza()

            : base("Болгарская пицца")

        { }

        public override int GetCost()

        {

            return 8;

        }

    }

    abstract class PizzaDecorator : Pizza

    {

        protected Pizza pizza;

        public PizzaDecorator(string n, Pizza pizza) : base(n)

        {

            this.pizza = pizza;

        }

    }

    class TomatoPizza : PizzaDecorator

    {

        public TomatoPizza(Pizza p)

            : base(p.Name + ", с томатами", p)

        { }

     

        public override int GetCost()

        {

            return pizza.GetCost() + 3;

        }

    }

    class CheesePizza : PizzaDecorator

    {

        public CheesePizza(Pizza p)

            : base(p.Name + ", с сыром", p)

        { }

     

        public override int GetCost()

        {

            return pizza.GetCost() + 5;

        }

    }

    В качестве компонента здесь выступает абстрактный класс Pizza, который определяет базовую функциональность в виде свойства Name и метода GetCost(). Эта функциональность реализуется двумя подклассами ItalianPizza и BulgerianPizza, в которых жестко закодированы название пиццы и ее цена.

    Декоратором является абстрактный класс PizzaDecorator, который унаследован от класса Pizza и содержит ссылку на декорируемый объект Pizza. В отличие от формальной схемы здесь установка декорируемого объекта происходит не в методе SetComponent, а в конструкторе.

    Отдельные функциональности - добавление томатов и сыры к пиццам реализованы через классы TomatoPizza и CheesePizza, которые обертывают объект Pizza и добавляют к его имени название добавки, а к цене - стоимость добавки, то есть переопределяя метод GetCost и изменяя значение свойства Name.

    Pizza pizza3 = new BulgerianPizza();

    pizza3 = new TomatoPizza(pizza3);

    pizza3 = new CheesePizza(pizza3);


    23. Шаблон проектирования Наблюдатель (Observer). Назначение. Пример использования.

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

    Когда использовать:

    • Когда система состоит из множества классов, объекты которых должны находиться в согласованных состояниях

    • Когда общая схема взаимодействия объектов предполагает две стороны: одна рассылает сообщения и является главным, другая получает сообщения и реагирует на них. Отделение логики обеих сторон позволяет их рассматривать независимо и использовать отдельно друга от друга.

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

    UML



    • IObservable: представляет наблюдаемый объект. Определяет три метода: AddObserver() (для добавления наблюдателя), RemoveObserver() (удаление набюдателя) и NotifyObservers() (уведомление наблюдателей)

    • ConcreteObservable: конкретная реализация интерфейса IObservable. Определяет коллекцию объектов наблюдателей.

    • IObserver: представляет наблюдателя, который подписывается на все уведомления наблюдаемого объекта. Определяет метод Update(), который вызывается наблюдаемым объектом для уведомления наблюдателя.

    • ConcreteObserver: конкретная реализация интерфейса IObserver.

    При этом наблюдаемому объекту не надо ничего знать о наблюдателе кроме того, что тот реализует метод Update(). С помощью отношения агрегации реализуется слабосвязанность обоих компонентов. Изменения в наблюдаемом объекте не виляют на наблюдателя и наоборот.

    В определенный момент наблюдатель может прекратить наблюдение. И после этого оба объекта - наблюдатель и наблюдаемый могут продолжать существовать в системе независимо друг от друга.

    Пример:

    1. class Program

    2. {

    3. static void Main(string[] args)

    4. {

    5. Stock stock = new Stock();

    6. Bank bank = new Bank("ЮнитБанк", stock);

    7. Broker broker = new Broker("Иван Иваныч", stock);

    8. // имитация торгов

    9. stock.Market();

    10. // брокер прекращает наблюдать за торгами

    11. broker.StopTrade();

    12. // имитация торгов

    13. stock.Market();

    14.

    15. Console.Read();

    16. }

    17. }

    18.

    19. interface IObserver

    20. {

    21. void Update(Object ob);

    22. }

    23.

    24. interface IObservable

    25. {

    26. void RegisterObserver(IObserver o);

    27. void RemoveObserver(IObserver o);

    28. void NotifyObservers();

    29. }

    30.

    31. class Stock : IObservable

    32. {

    33. StockInfo sInfo; // информация о торгах

    34.

    35. List observers;

    36. public Stock()

    37. {

    38. observers = new List();

    39. sInfo= new StockInfo();

    40. }

    41. public void RegisterObserver(IObserver o)

    42. {

    43. observers.Add(o);

    44. }

    45.

    46. public void RemoveObserver(IObserver o)

    47. {

    48. observers.Remove(o);

    49. }

    50.

    51. public void NotifyObservers()

    52. {

    53. foreach(IObserver o in observers)

    54. {

    55. o.Update(sInfo);

    56. }

    57. }

    58.

    59. public void Market()

    60. {

    61. Random rnd = new Random();

    62. sInfo.USD = rnd.Next(20, 40);

    63. sInfo.Euro = rnd.Next(30, 50);

    64. NotifyObservers();

    65. }

    66. }

    67.

    68. class StockInfo

    69. {

    70. public int USD { get; set; }

    71. public int Euro { get; set; }

    72. }

    73.

    74. class Broker : IObserver

    75. {

    76. public string Name { get; set; }

    77. IObservable stock;

    78. public Broker(string name, IObservable obs)

    79. {

    80. this.Name = name;

    81. stock = obs;

    82. stock.RegisterObserver(this);

    83. }

    84. public void Update(object ob)

    85. {

    86. StockInfo sInfo = (StockInfo)ob;

    87.

    88. if(sInfo.USD>30)

    89. Console.WriteLine("Брокер {0} продает доллары; Курс доллара: {1}", this.Name, sInfo.USD);

    90. else

    91. Console.WriteLine("Брокер {0} покупает доллары; Курс доллара: {1}", this.Name, sInfo.USD);

    92. }

    93. public void StopTrade()

    94. {

    95. stock.RemoveObserver(this);

    96. stock=null;

    97. }

    98. }

    99.

    100. class Bank : IObserver

    101. {

    102. public string Name { get; set; }

    103. IObservable stock;

    104. public Bank(string name, IObservable obs)

    105. {

    106. this.Name = name;

    107. stock = obs;

    108. stock.RegisterObserver(this);

    109. }

    110. public void Update(object ob)

    111. {

    112. StockInfo sInfo = (StockInfo)ob;

    113.

    114. if (sInfo.Euro > 40)

    115. Console.WriteLine("Банк {0} продает евро; Курс евро: {1}", this.Name, sInfo.Euro);

    116. else

    117. Console.WriteLine("Банк {0} покупает евро; Курс евро: {1}", this.Name, sInfo.Euro);

    118. }

    119. }

    Итак, здесь наблюдаемый объект представлен интерфейсом IObservable, а наблюдатель - интерфейсом IObserver. Реализацией интерфейса IObservable является класс Stock, который символизирует валютную биржу. В этом классе определен метод Market(), который имитирует торги и инкапсулирует всю информацию о валютных курсах в объекте StockInfo. После проведения торгов производится уведомление всех наблюдателей.

    Реализациями интерфейса IObserver являются классы Broker, представляющий брокера, и Bank, представляющий банк. При этом метод Update() интерфейса IObserver принимает в качестве параметра некоторый объект. Реализация этого метода подразумевает получение через данный параметр объекта StockInfo с текущей информацией о торгах и произведение некоторых действий: покупка или продажа долларов и евро. Дело в том, что часто необходимо информировать наблюдателя об изменении состояния наблюдаемого объекта. В данном случае состояние заключено в объекте StockInfo. И одним из вариантом информирования наблюдателя о состоянии является push-модель, при которой наблюдаемый объект передает (иначе говоря толкает - push) данные о своем состоянии, то есть передаем в виде параметра метода Update().
    1   2   3   4   5   6


    написать администратору сайта