Разделы презентаций


Принцип разделения интерфейса  ( The Interface Segregation Principle )

Содержание

Принципы

Слайды и текст этой презентации

Слайд 1Принцип разделения интерфейса (The Interface Segregation Principle)
«много интерфейсов, специально предназначенных для

клиентов, лучше, чем один интерфейс общего назначения.»

Принцип разделения интерфейса (The Interface Segregation Principle) «много интерфейсов, специально предназначенных для клиентов, лучше, чем один интерфейс общего

Слайд 2Принципы

Принципы

Слайд 3Содержание
ISP
Примеры
Лишняя абстракция в наследовании
«Жирный» интерфейс
Паттерн Adapter
Паттерн Стратегия
Литература

СодержаниеISPПримерыЛишняя абстракция в наследовании«Жирный» интерфейсПаттерн AdapterПаттерн СтратегияЛитература

Слайд 4Пример
public interface IEmployee { bool AddDetailsEmployee(); }
Допустим все классы

Employee наследуют этот интерфейс для сохранения данных.
Теперь предположим, что

компания однажды сказала вам, что они хотят читать данные только для сотрудников в должности senior.
Что вы будете делать, просто добавьте один метод в этот интерфейс?
public interface IEmployee {
bool AddDetailsEmployee();
bool ShowDetailsEmployee(int id); }
Но теперь пусть необходимо, объектам JuniorEmployee читать свои данные из базы данных.
Решение заключается в том, чтобы передать эту ответственность другому интерфейсу:
public interface IOperationAdd { bool AddDetailsEmployee (); }
public interface IOperationGet { bool ShowDetailsEmployee (int id); }

Примерpublic interface IEmployee { bool AddDetailsEmployee(); } Допустим все классы Employee наследуют этот интерфейс для сохранения данных.

Слайд 5Лишняя абстракция в наследовании
Проблема
Речь идет о базовых классах, которые вынуждают

своих наследников знать и делать слишком много.
Представим, - есть

базовый класс для аудиторов EntityAuditor.
Он унаследован от класса AuditorBase, который предоставляет ORM, и реализует метод AuditEntityFieldSet этого базового класса.
Также EntityAuditor добавляет свой абстрактный метод CreateLogRow, который используется в методе AuditEntityFieldSet и должен быть переопределен в конкретных реализациях.

Лишняя абстракция в наследовании ПроблемаРечь идет о базовых классах, которые вынуждают своих наследников знать и делать слишком

Слайд 6EntityAuditor добавляет свой абстрактный метод CreateLogRow
public abstract class EntityAuditor extends

AuditorBase
{@Qverride
    public void AuditEntityFieldSet(IEntityCore entity, int fieldIndex, object originalValue)
    {
        // ...
                CreateLogRow(...
                 //

...
    }
      protected abstract LogRowEntity CreateLogRow(int fieldId, string oldValue, string newValue, IEntityCore entity);
}
EntityAuditor добавляет свой абстрактный метод CreateLogRowpublic abstract class EntityAuditor extends AuditorBase{@Qverride     public void AuditEntityFieldSet(IEntityCore entity, int fieldIndex,

Слайд 7После этого начинаем реализовывать наследников.
Например, создадим аудитор для класса

Product:
public class ProductAuditor extends EntityAuditor
{@override
    protected LogRowEntity CreateLogRow(int fieldId, string oldValue,

string newValue, IEntityCore entity)
    {
        // ...
    }
}
Сейчас добавлению наследников ничего не мешает.
Теперь представим, что в методе AuditEntityFieldSet понадобилась дополнительная логика, при которой нужно вызвать метод UpdateDuplicates.

После этого начинаем реализовывать наследников. Например, создадим аудитор для класса Product:public class ProductAuditor extends EntityAuditor{@override    protected LogRowEntity CreateLogRow(int

Слайд 8UpdateDuplicates является абстрактным и требует реализации в наследниках
public abstract class

EntityAuditor extends AuditorBase{
    public override void AuditEntityFieldSet(IEntityCore entity, int fieldIndex, object

originalValue)    {        // ...
           CreateLogRow(...
          UpdateDuplicates(…                 // …    }
      protected abstract LogRowEntity CreateLogRow(int fieldId, string oldValue, string newValue, IEntityCore entity);
  
    protected abstract void UpdateDuplicates(IEntityCore entity, int fieldId, object current);}
    
public class ProductAuditor extends EntityAuditor{

    protected LogRowEntity CreateLogRow(int fieldId , string oldValue, string newValue, IEntityCore entity)    {        // …    }
      protected void UpdateDuplicates(IEntityCore entity, int fieldId ,object current)    {
        // реализация    }}
  public class AccountAuditor extends EntityAuditor{
    protected LogRowEntity CreateLogRow(int fieldId, string oldValue, string newValue, IEntityCore entity)    {        // …    }
      protected void UpdateDuplicates(IEntityCore entity, int fieldId, object current)    {        // здесь ничего нет!    }}

UpdateDuplicates является абстрактным и требует реализации в наследникахpublic abstract class EntityAuditor extends AuditorBase{    public override void AuditEntityFieldSet(IEntityCore entity,

Слайд 9EntityAuditor требует реализации метода
UpdateDuplicates даже в тех наследниках, где

он не нужен, как, например, в AccountAuditor.
Проблема в том,

что частный случай (UpdateDuplicates), который используется только в половине наследников, мы сделали общим, т.е. обязательным для всех наследников нашего EntityAuditor.
Получается, что чем больше наследников будет у EntityAuditor, тем больше бесполезного кода мы будем писать, тем больше наследники будут знать лишнего о своем базовом классе.
Это может сильно помешать нам в дальнейшем при рефакторинге или изменении логики в EntityAuditor.
EntityAuditor требует реализации метода UpdateDuplicates даже в тех наследниках, где он не нужен, как, например, в AccountAuditor.

Слайд 10Решение
Создадим новый интерфейсный тип
Interface IUpdateDuplicates{
protected void UpdateDuplicates(IEntityCore entity, int fieldId,

object current)}

public abstract class EntityAuditor extends AuditorBase implements IUpdateDuplicate
{
    public

override void AuditEntityFieldSet(IEntityCore entity, int fieldIndex, object originalValue)
    {        // ...
         CreateLogRow(…  
        UpdateDuplicates(…     
        // …    }
      protected abstract LogRowEntity CreateLogRow(decimalfi eldId, string oldValue, string newValue, IEntityCore entity);
  
    protected void UpdateDuplicates(IEntityCore entity, int fieldId, object current);   }

РешениеСоздадим новый интерфейсный типInterface IUpdateDuplicates{protected void UpdateDuplicates(IEntityCore entity, int fieldId, object current)}public abstract class EntityAuditor extends AuditorBase

Слайд 11«Жирный» интерфейс
Проблема
У нас есть интерфейс ISpecification. С помощью него мы

можем узнать подходит ли продукт заявке – метод IsSuitable и

является ли поле продукта измененным – метод IsFieldChanged:

public interface ISpecification
{
    boolean IsSuitable(Product realty, Offer offer);
     
    boolean IsFieldChanged(Product oldValue, Product newValue);
}

«Жирный» интерфейс ПроблемаУ нас есть интерфейс ISpecification. С помощью него мы можем узнать подходит ли продукт заявке

Слайд 12Клиенты
Чем является наш модуль для сторонних клиентов? Он является набором

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

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

public class ProductRepository implements IRepository{
    public void Save(Product product)    {
        // ...
          specification.IsFieldChanged(…          // …    }}
  ///
/// Программа расчета подходящих продуктов
///

public class Program{
    public static void Main(string[] args)    {        // ...
          specification.IsSuitable(…    }}

КлиентыЧем является наш модуль для сторонних клиентов? Он является набором интерфейсов, с помощью которых модуль может быть

Слайд 13Допустим, что мы уже написали несколько конкретных спецификаций:
class PriceSpecification implements

ISpecification
{
    public bool IsSuitable(Product realty, Offer offer)
    {
        // ...
    }
      public bool IsFieldChanged(Product oldValue,

Product newValue)
    {
        // ...
    }
}
  
Допустим, что мы уже написали несколько конкретных спецификаций:class PriceSpecification implements ISpecification{    public bool IsSuitable(Product realty, Offer offer)    {        // ...    }      public

Слайд 14Полученный результат нас не устраивает
При рефакторинге или изменинии логики в

консольном приложении и методе IsSuitable, нам придется затронуть все классы,

которые реализовали интерфейс ISpecification.
Например, представьте, что будет если в метод IsSuitable мы захотим добавить еще один параметр?
А если конкретных спецификаций накопилось уже с десяток?
Основная мысль в том, что теперь различные части системы зависят друг от друга, хоть и косвенно.
Консольное приложение зависит от логики хранилища и наоборот.
Полученный результат нас не устраиваетПри рефакторинге или изменинии логики в консольном приложении и методе IsSuitable, нам придется

Слайд 15Решение
Главное правило в данном случае звучит так: если клиенты интерфейса

разделены, то и интерфейс должен быть разделен соответствующим образом.

РешениеГлавное правило в данном случае звучит так: если клиенты интерфейса разделены, то и интерфейс должен быть разделен

Слайд 16После разделения получаем:
public interface ISpecification
{
    boolean IsSuitable(Product realty, Offer offer);
}
  
public

interface IChangeFieldDetector
{
    boolean IsFieldChanged(Product oldValue, Product newValue);
}

После разделения получаем: public interface ISpecification{    boolean IsSuitable(Product realty, Offer offer);}  public interface IChangeFieldDetector{    boolean IsFieldChanged(Product oldValue, Product newValue);}

Слайд 17Решение проблемы с зависимостью
Теперь консольное приложение работает c интерфейсом ISpecification,

а хранилище работает с интерфейсом IChangeFieldDetector. Проблема с зависимостью решена.
Кроме

этого, мы решили еще и проблему с наследниками первой реализации ISpecification. Теперь класс может реализовывать только один интерфейс, за счет чего его на много проще поддерживать:

Решение проблемы с зависимостьюТеперь консольное приложение работает c интерфейсом ISpecification, а хранилище работает с интерфейсом IChangeFieldDetector. Проблема

Слайд 18Класс реализует только один интерфейс
class PriceSpecification implements ISpecification
{
    public boolean IsSuitable(Product

realty, Offer offer)
    {
        // ...
    }
}
 class PriceChangeFieldDetector implements IChangeFieldDetector
{
    public boolean IsFieldChanged(Product oldValue,

Product newValue)
    {
        // ...
    }
}

Класс реализует только один интерфейсclass PriceSpecification implements ISpecification{    public boolean IsSuitable(Product realty, Offer offer)    {        // ...    }} class PriceChangeFieldDetector implements IChangeFieldDetector{    public

Слайд 19Adapter (Wrapper)
Адаптер — это структурный паттерн проектирования, который обеспечивает совместную

работу классов с несовместимыми интерфейсами.
Проблема
К вашему приложению, работающему с данными

в XML, нужно прикрутить стороннюю библиотеку, работающую в JSON.
Например, ваше приложение скачивает биржевые котировки из нескольких источников в XML и рисует красивые графики.
В какой-то момент вы решаете улучшить приложение, применив стороннюю библиотеку аналитики. Предположим - библиотека поддерживает только JSON формат данных.

Adapter (Wrapper)Адаптер — это структурный паттерн проектирования, который обеспечивает совместную работу классов с несовместимыми интерфейсами.ПроблемаК вашему приложению,

Слайд 20Решение
Вы смогли бы просто переписать её для поддержки XML.
Но

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

от библиотеки.
А во-вторых, у вас может просто не быть доступа к её исходникам.

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

Решение Вы смогли бы просто переписать её для поддержки XML. Но во-первых, это может нарушить работу существующего

Слайд 21Иногда возможно создать даже двухсторонний адаптер, который работал бы в

обе стороны

Таким образом, в приложении биржевых котировок, вы могли бы

создать класс XML_To_JSON_Adapter, который бы оборачивал класс библиотеки аналитики.
Ваш код посылал бы запросы этому объекту в XML, а адаптер бы сначала транслировал входящие данные в JSON, а затем передавал бы их определённым методам библиотеки.

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

Слайд 22Object Adapter
Object Adapter достигает своей цели с помощью композиции. На

диаграмме, представленной ниже, клиенту требуется использовать интерфейс TargetInterface.
Для этого

создается класс ObjectAdapter, который реализует интерфейс TargetInterface, а также хранит объект класса Adaptee.
При вызове метода targetMethod у Адаптера, осуществляется вызов соответствующего метода у адаптируемого интерфейса.

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

Слайд 23В самом простом случае реализация ObjectAdapter будет такой
public class ObjectAdapter

implements TargetInterface {
private Adaptee adaptee;
public void targetMethod() {


adaptee.method()
} }
Плюс такого подхода в том, что мы полностью отделяем клиентский интерфейс от адаптируемого интерфейса.
В самом простом случае реализация ObjectAdapter будет такойpublic class ObjectAdapter implements TargetInterface { private Adaptee adaptee; public

Слайд 24В случае с Class Adapter'ом, для достижения нашей цели используется

множественное наследование.
ClassAdapter наследуется от клиентского интерфейса и от

Адаптируемого интерфейса.
Так как в Java нет множественного наследования, то только один из предков может быть абстрактным/конкретным классом.
Второй предок будет интерфейсом, что не всегда удобно.
Диаграмма классов:

В случае с Class Adapter'ом, для достижения нашей цели используется множественное наследование. ClassAdapter наследуется от клиентского интерфейса

Слайд 25Реализация класса ClassAdapter:
public class ClassAdapter extends Adaptee implements TargetInterface {

public void targetMethod() {
method(); } }
При такой реализации

адаптера может возникнуть конфликт сигратур методов.
Такой проблемы у Object Adapter нет.
Class Adapter считается более простым решением в случае когда не требуется жесткого разделения клиентского и адаптируемого интерфейсов.

Реализация класса ClassAdapter:public class ClassAdapter extends Adaptee implements TargetInterface { public void targetMethod() { method(); } }

Слайд 26Применимость
Паттерн можно часто встретить в Java-коде, особенно там, где требуется

конвертация разных типов данных или совместная работа классов с разными

интерфейсами.
Примеры Адаптеров в стандартных библиотеках Java:
java.util.Arrays#asList()
java.util.Collections#list()
java.util.Collections#enumeration()
java.io.InputStreamReader(InputStream) (возвращает объект Reader)
java.io.OutputStreamWriter(OutputStream) (возвращает объект Writer)
javax.xml.bind.annotation.adapters.XmlAdapter#marshal() и #unmarshal()
ПрименимостьПаттерн можно часто встретить в Java-коде, особенно там, где требуется конвертация разных типов данных или совместная работа

Слайд 27Признаки применения паттерна
Адаптер получает конвертируемый объект в конструкторе или

через параметры своих методов.
Методы Адаптера обычно совместимы с интерфейсом

одного объекта.
Они делегируют вызовы вложенному объекту, превратив перед этим параметры вызова в формат, поддерживаемый вложенным объектом.


Признаки применения паттерна Адаптер получает конвертируемый объект в конструкторе или через параметры своих методов. Методы Адаптера обычно

Слайд 28Практическая задача
Задан некоторый класс — SequenceGenerator, генерирующий последовательности целых чисел,

по определенному закону — это и есть наш клиент.
Есть

интерфейс — Generator, который использует клиент непосредственно для генерации каждого отдельного элемента последовательности — это наш клиентский интерфейс.
Есть класс RandomGenerator, который уже умеет генерировать случайные числа.
SequenceGenerator не может использовать RandomGenerator для генерации элементов, потому что он не соответствует клиентскому интерфейсу.
Наша задача — написать адаптер RandomGenerator к SequenceGenerator.
Практическая задачаЗадан некоторый класс — SequenceGenerator, генерирующий последовательности целых чисел, по определенному закону — это и есть

Слайд 29Class SequenceGenerator
Классическая реализация паттерна Class Adapter подразумевает использование множественного наследования.

В Java, можно воспользоваться имплементацией интерфейсов.
public interface Generator {   public int next(); } public class SequenceGenerator {      private Generator generator;   public SequenceGenerator(Generator

generator) {     super();     this.generator = generator;   }
Class SequenceGeneratorКлассическая реализация паттерна Class Adapter подразумевает использование множественного наследования. В Java, можно воспользоваться имплементацией интерфейсов.

Слайд 30Class RandomGenerator
public int[] generate(int length) {     int ret[] = new int[length];          for (int i=0; i

{      public int getRandomNumber() {     return 4;       } }

Class RandomGeneratorpublic int[] generate(int length) {     int ret[] = new int[length];          for (int i=0; i

Слайд 31class RandomGeneratorAdapter
public class RandomGeneratorAdapter extends RandomGenerator implements Generator {   @Override   public int next() {     return getRandomNumber();   }   } // Использование public class Main {   public static void main(String[] args)

{          RandomGeneratorAdapter adapter = new RandomGeneratorAdapter();         SequenceGenerator generator = new SequenceGenerator(adapter);          for (int i: generator.generate(10)) {       System.out.print(i + " ");     }   } }

class RandomGeneratorAdapterpublic class RandomGeneratorAdapter extends RandomGenerator implements Generator {   @Override   public int next() {     return getRandomNumber();   }   }  // Использование public class Main {

Слайд 32Стратегия
Стратегия — это поведенческий паттерн, выносит набор алгоритмов в собственные

классы и делает их взаимозаменяемыми.
Другие объекты содержат ссылку на объект-стратегию

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

СтратегияСтратегия — это поведенческий паттерн, выносит набор алгоритмов в собственные классы и делает их взаимозаменяемыми.Другие объекты содержат

Слайд 33Применимость
Стратегия часто используется в Java коде, особенно там, где нужно

подменять алгоритм во время выполнения программы..
Примеры Стратегии в стандартных библиотеках

Java:
java.util.Comparator#compare(), вызываемые из Collections#sort().
javax.servlet.http.HttpServlet: метод service(), а также все методы doXXX()принимают объекты HttpServletRequest и HttpServletResponse в параметрах.
javax.servlet.Filter#doFilter()
Признаки применения паттерна: Класс делегирует выполнение вложенному объекту абстрактного типа или интерфейса.

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

Слайд 34Пример: Методы оплаты в интернет магазине
В этом примере Стратегия реализует выбор

платёжного метода в интернет магазине.
Когда пользователь сформировал заказ, он

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

Пример: Методы оплаты в интернет магазинеВ этом примере Стратегия реализует выбор платёжного метода в интернет магазине. Когда пользователь

Слайд 35PayStrategy.java: Общий интерфейс стратегий оплаты
package strategy.example.strategies;
/* Общий интерфейс всех стратегий.

*/ public interface PayStrategy {
boolean pay(int paymentAmount);
void collectPaymentDetails();

}
PayStrategy.java: Общий интерфейс стратегий оплаты package strategy.example.strategies; /* Общий интерфейс всех стратегий. */ public interface PayStrategy { boolean

Слайд 36PayByPayPal.java: Оплата через PayPal
package strategy.example.strategies;
import java.io.*;
import java.util.*;
public class

PayByPayPal implements PayStrategy {
private static final Map DATA_BASE

= new HashMap<>();
private final BufferedReader READER = new BufferedReader(new InputStreamReader(System.in));
private String email;
private String password;
private boolean signedIn;
static {
DATA_BASE.put("amanda1985", "amanda@ya.com");
DATA_BASE.put("qwerty", "john@amazon.eu");
}
PayByPayPal.java: Оплата через PayPal package strategy.example.strategies; import java.io.*; import java.util.*; public class PayByPayPal implements PayStrategy { private static

Слайд 37 Собираем данные от клиента.
@Override
public void collectPaymentDetails() {


try { while (!signedIn) {
System.out.print("Enter user email: ");
email

= READER.readLine();
System.out.print("Enter password: ");
password = READER.readLine();
if (verify()) { System.out.println("Data verification was successful"); }
else { System.out.println("Wrong email or password!"); }
} }
catch (IOException ex) { ex.printStackTrace();
} }
Собираем данные от клиента. @Override public void collectPaymentDetails() { try { while (!signedIn) { System.out.print(

Слайд 38Если клиент уже вошел в систему, то для следующей оплаты

данные вводить * не придется
private boolean verify()
{ setSignedIn(email.equals(DATA_BASE.get(password)));
return

signedIn; }
@Override
public boolean pay(int paymentAmount) {
if (signedIn) { System.out.println("Paying " + paymentAmount + " using PayPal");
return true; }
else { return false; } }
private void setSignedIn(boolean signedIn) {
this.signedIn = signedIn; } }
Если клиент уже вошел в систему, то для следующей оплаты данные вводить * не придетсяprivate boolean verify()

Слайд 39strategies/PayByCreditCard.java: Оплата кредиткой
package strategy.example.strategies;
import java.io.*;
/** * Конкретная стратегия.

Реализует оплату корзины интернет магазина кредитной * картой клиента. */

public class PayByCreditCard implements PayStrategy {
private final BufferedReader READER = new BufferedReader(new InputStreamReader(System.in));
private CreditCard card;
strategies/PayByCreditCard.java: Оплата кредиткой package strategy.example.strategies; import java.io.*; /** * Конкретная стратегия. Реализует оплату корзины интернет магазина кредитной

Слайд 40/** Собираем данные карты клиента. */
@Override
public void collectPaymentDetails()

{
try { System.out.print("Enter card number: ");
String number =

READER.readLine();
System.out.print("Enter date 'mm/yy': ");
String date = READER.readLine();
System.out.print("Enter cvv code: ");
String cvv = READER.readLine();
card = new CreditCard(number, date, cvv);
/** Собираем данные карты клиента. */ @Override public void collectPaymentDetails() { try { System.out.print(

Слайд 41// Валидируем номер карты.
} catch (IOException ex) { ex.printStackTrace();

} }
/** * После проверки карты мы можем совершить

оплату. Если клиент продолжает * покупки, мы не запрашиваем карту заново. */
@Override
public boolean pay(int paymentAmount) {
if (cardIsPresent()) { System.out.println("Paying " + paymentAmount + " using Credit Card");
card.setAmount(card.getAmount() - paymentAmount);
return true;
} else { return false; } }
private boolean cardIsPresent() { return card != null; } }
// Валидируем номер карты. } catch (IOException ex) { ex.printStackTrace(); } } /** * После проверки карты

Слайд 42CreditCard.java: Кредитная карта
package strategy.example.strategies;
public class CreditCard {
private int amount;

private String number;
private String date;
private String cvv;
public

CreditCard(String number, String date, String cvv) {
this.amount = 100_000;
this.number = number;
this.date = date;
this.cvv = cvv; }
public void setAmount(int amount) {
this.amount = amount; }
public int getAmount() { return amount; } }

CreditCard.java: Кредитная картаpackage strategy.example.strategies; public class CreditCard { private int amount; private String number; private String date; private

Слайд 43Order.java: Класс заказа
package strategy.example.order;
import strategy.example.strategies.PayStrategy;
/** * Класс заказа. Ничего

не знает о том каким способом (стратегией) будет * расчитыватся

клиент, а просто вызывает метод оплаты. Все остальное стратегия * делает сама. */
public class Order {
private static int totalCost = 0;
private boolean isClosed = false;
public void processOrder(PayStrategy strategy) {
strategy.collectPaymentDetails();
// Здесь мы могли бы забрать и сохранить платежные данные из стратегии.
}
Order.java: Класс заказаpackage strategy.example.order; import strategy.example.strategies.PayStrategy; /** * Класс заказа. Ничего не знает о том каким способом (стратегией)

Слайд 44Класс заказа
public void setTotalCost(int cost) {
this.totalCost += cost; }


public static int getTotalCost() {
return totalCost; }
public boolean

isClosed() {
return isClosed; }
public void setClosed() {
isClosed = true; } }

Класс заказаpublic void setTotalCost(int cost) { this.totalCost += cost; } public static int getTotalCost() { return totalCost;

Слайд 45Клиентский код
package strategy.example;
import strategy.example.order.Order;
import strategy.example.strategies.PayByCreditCard;
import strategy.example.strategies.PayByPayPal;
import

strategy.example.strategies.PayStrategy;
import java.io.*;
import java.util.*;
public class Demo {
public

static Map priceOnProducts = new HashMap<>();
public static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
private static Order order = new Order();
private static PayStrategy strategy;
Клиентский кодpackage strategy.example; import strategy.example.order.Order; import strategy.example.strategies.PayByCreditCard; import strategy.example.strategies.PayByPayPal; import strategy.example.strategies.PayStrategy; import java.io.*; import java.util.*; public class

Слайд 46Начальные данные
static {
priceOnProducts.put(1, 2200);
priceOnProducts.put(2, 1850);
priceOnProducts.put(3, 1100);
priceOnProducts.put(4,

890); }
public static void main(String[] args) throws IOException {


while (!order.isClosed()) {
int cost; String continueChoice;
do { System.out.print("Select a product:" + "\n" + "1 - Mother board" + "\n" + "2 - CPU" + "\n" + "3 - HDD" + "\n" + "4 - Memory" + "\n");
int choice = Integer.parseInt(reader.readLine());
cost = priceOnProducts.get(choice);
System.out.print("Count: ");
int count = Integer.parseInt(reader.readLine());
order.setTotalCost(cost * count); System.out.print("You wish to continue selection? Y/N: ");
Начальные данныеstatic { priceOnProducts.put(1, 2200); priceOnProducts.put(2, 1850); priceOnProducts.put(3, 1100); priceOnProducts.put(4, 890); } public static void main(String[] args)

Слайд 47Выбор стратегий
continueChoice = reader.readLine(); }
while (continueChoice.equalsIgnoreCase("Y"));
if (strategy

== null) { System.out.println("Select a Payment Method" + "\n" +

"1 - PalPay" + "\n" + "2 - Credit Card");
String paymentMethod = reader.readLine();
// Клиент создаёт различные стратегии на основании
// пользовательских данных, конфигурации и прочих параметров.
if (paymentMethod.equals("1")) {
strategy = new PayByPayPal();
} else if (paymentMethod.equals("2")) {
strategy = new PayByCreditCard(); }
// Объект заказа делегирует сбор платёжных данных стратегии, т.к.
// только стратегии знают какие данные им нужны для
// приёма оплаты. order.processOrder(strategy); }
System.out.print("Pay " + Order.getTotalCost() + " units or Continue shopping? P/C: ");
String proceed = reader.readLine();
if (proceed.equalsIgnoreCase("P")) {
// И наконец, стратегия запускает приём платежа.
if (strategy.pay(Order.getTotalCost())) {
System.out.println("Payment has succeeded"); }
else { System.out.println("FAIL! Check your data");
} order.setClosed(); } } } }

Выбор стратегий continueChoice = reader.readLine(); } while (continueChoice.equalsIgnoreCase(

Слайд 48Литература
https://refactoring.guru/ru/design-patterns

Литератураhttps://refactoring.guru/ru/design-patterns

Обратная связь

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

Email: Нажмите что бы посмотреть 

Что такое TheSlide.ru?

Это сайт презентации, докладов, проектов в PowerPoint. Здесь удобно  хранить и делиться своими презентациями с другими пользователями.


Для правообладателей

Яндекс.Метрика