dreamworker

java PECS

Aug 29th, 2019
284
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 9.66 KB | None | 0 0
  1. package ru.home.pecs.test04;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.List;
  5.  
  6.  
  7.  
  8.  
  9. // PECS - producer extend, consumer super
  10.  
  11.  
  12. class Plant {
  13.     @Override
  14.     public String toString() {
  15.         return "I am a Plant !!";
  16.     }
  17. }
  18.  
  19. class Fruit extends Plant {
  20.     @Override
  21.     public String toString() {
  22.         return "I am a Fruit !!";
  23.     }
  24. }
  25.  
  26. class Apple extends Fruit {
  27.     @Override
  28.     public String toString() {
  29.         return "I am an Apple !!";
  30.     }
  31. }
  32.  
  33.  
  34. class AsianApple extends Apple {
  35.     @Override
  36.     public String toString() {
  37.         return "I am an AsianApple !!";
  38.     }
  39. }
  40.  
  41.  
  42.  
  43.  
  44.  
  45. /*
  46.  
  47. // Inheritance diagram
  48. // наследование идет сверху вниз
  49.  
  50.  
  51.   Plant
  52.  
  53.     ^
  54.     |
  55.  
  56.   Fruit
  57.  
  58.     ^
  59.     |
  60.  
  61.   Apple
  62.  
  63.     ^
  64.     |
  65.  
  66. AsianApple
  67.  
  68.  */
  69.  
  70.  
  71.  
  72.  
  73.  
  74.  
  75. public class App
  76. {
  77.  
  78.     public static void main(String[] args) {
  79.  
  80.         new App();
  81.     }
  82.  
  83.  
  84.         private void howTo() {
  85.  
  86.  
  87.         // First read documents at
  88.         // https://howtodoinjava.com/java/generics/java-generics-what-is-pecs-producer-extends-consumer-super/        //
  89.         // or locally at
  90.         // doc/Java Generics PECS - Producer Extends Consumer Super - HowToDoInJava.html
  91.  
  92.  
  93.         // List of apples
  94.         List<Apple> apples = new ArrayList<>();
  95.         apples.add(new Apple());
  96.  
  97.         // Все ниже работает используя
  98.         // subtype polymorphism or inclusion polymorphism
  99.         // (В переменную базового класса можно пихать наследников, но не наоборот)
  100.  
  101.         // Здесь описаны ограничения внутри класса-generic
  102.  
  103.         // ========================================================
  104.  
  105.         // PRODUCER EXTENDS (UPPER BOUND) - корзина basket производит фрукты (с нашей точки зрения класса-generic)
  106.  
  107.         // We can assign a list of apples to a basket of fruits;
  108.         // because apple is subtype of fruit
  109.  
  110.         // положим яблоки в крозину для фруктов basket1
  111.         List<? extends Fruit> basket1 = apples;
  112.  
  113.  
  114.  
  115.         // basket1 объявлена как List<? extends Fruit> и это означает
  116.         // что в basket1 может лежать наследники(и сам) Fruit, но точно какой наследник - заранее не известно,
  117.         // поэтому компилятор не позволит обращаться к содержимому basket ниже(по диаграме) чем как к Fruit.
  118.  
  119.         // Here we know that in basket there is nothing but fruit(and upper)
  120.         for (Fruit fruit : basket1){
  121.  
  122.             System.out.println(fruit);
  123.         }
  124.  
  125.         // or plant
  126.         for (Plant plant : basket1){
  127.  
  128.             System.out.println(plant);
  129.         }
  130.  
  131.         // disallowed
  132.         for (Apple apple : basket1){
  133.             System.out.println(apples);
  134.         }
  135.  
  136.         // disallowed
  137.         for (AsianApple asianApple : basket1){
  138.             System.out.println(asianApple);
  139.         }
  140.  
  141.  
  142.  
  143.  
  144.         // Этот предел называется верхний
  145.         // (https://docs.oracle.com/javase/tutorial/java/generics/upperBounded.html)
  146.         // И это верно для клиентского кода - использующего этот обобщенный класс.
  147.         // Но при работе внутри generic-класса это утверждение инвертируется -
  148.         // можно работать с интервалом классов, ограниченных Fruit снизу включительно.
  149.         // <? extends Fruit> означает что мы можем внутри generic-класса
  150.         // использовать вместо ? => [Plant, Fruit]
  151.         //
  152.         //
  153.         // Весьма напоминает linux pipes (конвеер) |
  154.         // Если мы берем вывод программы1 и перенаправляем его на вход программы2
  155.         // program1 | program2
  156.         // То это означает что данные которые были в stdout в 1 программе
  157.         // попадают в stdin второй программы.
  158.         // Такая же аналогия с InputStream / OutputStream
  159.         //
  160.         // Что это - входные или выходные данные, верхняя или нижняя граница -
  161.         // все зависит, с какой стороны мы смотрим - со стороны клиента или generic-класса
  162.  
  163.  
  164.  
  165.         // корзина - производитель, она отказывается потреблять
  166.         //disallowed all setters
  167.         basket1.add(new AsianApple());
  168.         basket1.add(new Apple());
  169.         basket1.add(new Fruit());
  170.         basket1.add(new Plant());
  171.  
  172.         // ========================================================
  173.  
  174.         // CONSUMER SUPER (LOWER BOUND) - корзина basket2 потребляет фрукты (берет у нас - с нашей точки зрения)
  175.  
  176.  
  177.         // We can assign a list of apples to a basket of apples
  178.         List<? super Apple> basket2 = apples;
  179.  
  180.  
  181.  
  182.         // disallowed all gets
  183.         // корзина - потребитель, она отказывается производить
  184.         //for (Plant plant : basket2){System.out.println(plant);}
  185.         //for (Fruit fruit : basket2){System.out.println(fruit);}
  186.         //for (Apple apple : basket2){System.out.println(apple);}
  187.         //for (AsianApple asianApple : basket2){System.out.println(asianApple);}
  188.  
  189.         // Корзина basket2 объявлена как предок корзины List<Apple>,
  190.         // Но заранее неизвестно, какой конкретно предок Apple будет использоваться
  191.         // (клиентским кодом, который будет юзать наш generic-класс)
  192.         // поэтому гарантированно в basket2 могут находиться классы начиная от Apple, заканчивая AsianApple
  193.         // <? super Apple> означает что мы можем использовать вместо ? => [Apple, AsianApple]
  194.  
  195.         basket2.add(new Fruit());      //Compile time error
  196.         basket2.add(new Plant());      //Compile time error
  197.  
  198.         basket2.add(new AsianApple()); //Successful
  199.         basket2.add(new Apple());      //Successful
  200.     }
  201.  
  202.     // Т.е. чтобы понять, с объектами какого типа мы можем работать (получать, передавать),
  203.     // необходимо инвертировать определение границ подстановки ?
  204.     // <? extends Class> - producer extends - можем обращаться к поставщику(supplier) за объектами [Object, Class]
  205.     //
  206.     // <? super Class> - consumer super - можем запихивать в потребителя объекты[Class, SubClass]
  207.  
  208.  
  209.     // Еще теории
  210.     // https://habr.com/ru/company/sberbank/blog/416413/
  211.  
  212.  
  213.     // =============================================================================
  214.     // Practice
  215.     // =============================================================================
  216.  
  217.  
  218.  
  219.  
  220.     // Практической применение:
  221.  
  222.     // -----------------------------------------------
  223.  
  224.     // метод потребляет яблоки клиентского кода
  225.     static void consume(List<? extends Apple> basket) {
  226.  
  227.         // Здесь корзина производитель
  228.         for(Fruit f : basket) {
  229.             System.out.println(f);
  230.         }
  231.     }
  232.  
  233.     // метод снабжает клиентский код яблоками
  234.     static void supply(List<? super Apple> basket) {
  235.  
  236.         //List<Apple> basket = new ArrayList<>();
  237.  
  238.         // Здесь корзина потребитель
  239.  
  240.         // disallowed
  241.         basket.add(new Plant());
  242.         // disallowed
  243.         basket.add(new Fruit());
  244.  
  245.         basket.add(new Apple());
  246.         basket.add(new AsianApple());
  247.     }
  248.  
  249.  
  250.     // Теперь перейдем к практическому использованию в клиентском коде:
  251.  
  252.  
  253.  
  254.  
  255.  
  256.  
  257.     App() {
  258.  
  259.         // Тут
  260.         // process(List<? extends Fruit> basket)
  261.         // basket будет потребитель для наших яблок
  262.         // basket принимает только Apple и выше - UPPER LIMIT - ограничение сверху
  263.  
  264.         // disallowed
  265.         List<Plant> plants = new ArrayList<>();
  266.         plants.add(new Apple());
  267.         consume(plants);
  268.         // disallowed
  269.         List<Fruit> fruits = new ArrayList<>();
  270.         fruits.add(new Apple());
  271.         consume(fruits);
  272.  
  273.         List<Apple> apples = new ArrayList<>();
  274.         apples.add(new Apple());
  275.         consume(apples);
  276.  
  277.         List<AsianApple> asianApples = new ArrayList<>();
  278.         asianApples.add(new AsianApple());
  279.         consume(asianApples);
  280.  
  281.  
  282.         // ==============================================
  283.  
  284.         List<Apple> basket = new ArrayList<>();
  285.  
  286.         supply(basket);
  287.  
  288.         // печатает все содержимое корзины
  289.         basket.forEach(System.out::println);
  290.  
  291.         // я бы все это назвал с точки зрения клиентского кода
  292.         // CEPS - consumer extends, producer super
  293.  
  294.     }
  295. }
Advertisement
Add Comment
Please, Sign In to add comment