julia_v_iluhina

Untitled

Sep 1st, 2016
102
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 18.10 KB | None | 0 0
  1. public interface LazyEntity<V> {
  2.     V getWrappedEntity();
  3. }
  4. /*
  5.     есть конвеншенсы по именам типов-дженериков
  6.     конвеншенcы
  7.     http://stackoverflow.com/questions/2900881/generic-type-parameter-naming-convention-for-java-with-multiple-chars
  8.     https://docs.oracle.com/javase/tutorial/java/generics/types.html
  9.  
  10.     тут уместнее
  11.     LazyEntity<T>
  12. */
  13. ********************************************
  14.  
  15. public interface LazyElementEntity extends LazyEntity<WebElement> {
  16. /*
  17.     логичнее этот интерфейс назвать LazyElement
  18.  
  19.     с классами-лейзи-элементами
  20.     как у нас будут обстоять дела
  21.  
  22.     лейзи-элементы любого вида - должны уметь то - что описано в interface LazyElementEntity
  23.     но - получать вебелемент мы будем - по-разному (фактически - реазицация getWrappedEntity)
  24.     например
  25.     мы уже реализовали - getWebDriver().findElement()
  26.     а будет еще и такой вариант  - получить вебэлемент - для такого лейзи-элемента
  27.         lazyElement.find(".destroy")
  28.         lazyCollection.find(cssClass("edited"))
  29.         lazyCollection.get(3)
  30.     т е - в итоге - у нас будет несколько классов, имплементирующих interface LazyElementEntity
  31.     причем - отличаться у них будут лишь конструкторы и  реазицация getWrappedEntity
  32.     а реализация остальных методов, да и вообще набор методов - один-в-один
  33.  
  34.     вот и получим такую иерархию
  35.  
  36.      самый общий интерфейс
  37.      LazyEntity<T>
  38.  
  39.         его потомки - интерфейсы
  40.             LazyElement
  41.             LazyCollection
  42.  
  43.             абстрактные классы
  44.                 AbstractLazyElement
  45.                 AbstractLazyCollection
  46.                 (реализуем все методы, кроме абстрактного getWrappedEntity,
  47.                  ну и конструктор нам тут не нужен - т к класс абстрактный)
  48.  
  49.                     набор классов - для элементов и коллекций
  50.                         наши уже разработанные варианты
  51.                             LazyWebDriverElement
  52.                             LazyWebDriverCollection
  53.  
  54.                         список будет пополняться)
  55.  
  56.      получишь что-то такое http://joxi.ru/GrqLOX3SNZPLoA
  57.      пока закрасила те классы - которые еще у нас не появилимь)
  58.      ну и разумно - это в рамках core - выделить в отдельный пекедж
  59.      wrappers - хорошее общее название
  60.      т к вот эти наши классы - это лишь обертка вокруг вебэлемента/списка вебэлементов
  61.  
  62.      есть конвеншенсы и по этому поводу - какие имена давать интерфейсу, какие - абстракному предку,
  63.      какие - классам-потомкам
  64.  
  65.      статья про это (лучший вариант)
  66.         http://www.vertigrated.com/blog/2011/02/interface-and-class-naming-anti-patterns-java-naming-convention-tautologies/
  67.      еще полезные линки
  68.          http://stackoverflow.com/questions/2814805/java-interfaces-implementation-naming-convention
  69.          https://web.archive.org/web/20130331071928/http://isagoksu.com/2009/development/java/naming-the-java-implementation-classes
  70.          http://programmers.stackexchange.com/questions/152759/should-i-add-an-abstract-prefix-to-my-abstract-classes
  71.  
  72.      Interfaces, abstract classes - good practice
  73.          http://stackoverflow.com/questions/1932247/abstract-classes-and-interfaces-best-practices-in-java
  74.          http://joxi.ru/E2pdR1lFB1pyM2
  75. */
  76. ******************************************
  77.  
  78.  @Override
  79.     public List<WebElement> shouldHave(Condition<List<WebElement>> condition) {
  80.         List<WebElement> elements;
  81.         elements = waitFor(this).until(condition);
  82.         return elements;
  83.     }
  84. /*
  85.     можно написать в одну строку
  86.     return waitFor(this).until(condition);
  87.  
  88.     а еще лучше - объявляй в интерфейсе и имплементируй метод с параметром Condition<List<WebElement>>... conditions
  89.  
  90.     кстати, заметь)
  91.     мы немного смухлевали в структуре для кондишенов)
  92.     CollectionCondition & ElementCondition - это как раз абстрактные классы-потомки конечных кондишенов
  93.     но - в именах этих классов - мы не указывали Abstract
  94.  
  95.     да и методы, возвращающие кондишены - нам возвращают не значение типа интерфейс - а
  96.     CollectionCondition или ElementCondition
  97.  
  98.     Если заморочиться на полную - можно и это подправить)
  99.     переименовать классы - CollectionCondition & ElementCondition
  100.     в AbstractCollectionCondition & AbstractElementCondition
  101.     а для того, чтобы наш фреймворк оперировал интерфейсными типами для кондишенов -
  102.  
  103.     дореализуем интерфейсы
  104.     CollectionCondition & ElementCondition
  105.         и уже методы из CollectionConditions & ElementConditions - будут возвращать значение типа интерфейс
  106.         CollectionCondition & ElementCondition
  107.     и в качестве типов параметров у методов should - будут использованы интерфейсы  CollectionCondition & ElementCondition
  108.  
  109.     ты, кстати, с интерфейсами фишку словила - параметр метода  shouldHave - интерфейс Condition<List<WebElement>>
  110.     молодец)
  111.  
  112.     ну и получаем варианты
  113.       1 - занудно выполнить все конвеншенсы - как я выше описала
  114.  
  115.       2 - оставить как сейчас +  использовать типы абстрактных классов CollectionCondition & ElementCondition -
  116.       как типы возвращаемых методами значений и типы параметров методов
  117.       Да, нарушены конвеншенсы
  118.       но, дело в том, что и в первом варианте - тоже не совсем все гладко)
  119.       ведь добавляемые в вариант 1 интерфейсы CollectionCondition & ElementCondition -
  120.       не используются как интерфейсы, от которых имплементированы классы
  121.  
  122.       т к оба варианта - с недостатками
  123.       но второй - лаконичнее - разумно использовать второй
  124.       а если хочется заморочиться и потренироваться - тогда первый))
  125. */
  126. *******************************
  127.  @Override
  128.     public WebElement shouldBe() {
  129.         return null;
  130.     }
  131. /*
  132.     добавь жизни этому методу))
  133.  
  134.     параметры и реализацию
  135. */
  136. ************************************
  137.  
  138.     public WaitFor(By locator) {
  139.         this.entity = new LazyElement(locator);
  140.     }
  141. /*
  142.     уже не нужен
  143.     посмотри = по-моему, не используется нигде
  144. */
  145. **************************************
  146.  
  147. public abstract class CollectionCondition extends AbstractCondition<List<WebElement>> {
  148.  
  149. ....
  150. //    @Override
  151. //    public List<WebElement> getWrappedEntity() {
  152. //        return getWebDriver().findElements(locator);
  153. //    }
  154. /*
  155.     избавляйся от этих комментариев - у кондишенов такого зверя теперь не будет)
  156.  
  157.     теперь все по уму - лейзи-объекты такое сами про себя рассказывают
  158. */
  159. *********************************
  160.  
  161. public class MinimumSizeOf extends SizeOf {
  162.  
  163.  ...
  164.     @Override
  165.     public List<WebElement> check(List<WebElement> wrappedEntity) {
  166. /*
  167.     а вот тут нам плохую службу сослужил рефакторинг)
  168.     в конечных кондишенах - лучше бы параметр назывался - elements - для списка
  169.     и element - для элемента
  170.  
  171.     пробегись и поправь
  172.  
  173.     а вот в рамках абстрактного класса термин wrappedEntity для этого параметра - наиболее точный
  174. */
  175. ******************************************
  176.  
  177. public abstract class AbstractCondition<V> implements Condition<V>{
  178.  
  179.     protected LazyEntity entity;
  180.  ....
  181. //    public String toString() {
  182. //        return String.format(getClass().getSimpleName() +
  183. //                "\nfor " + identity() + " found by " + locator +
  184. //                (expected() == "" ? "" : "\nexpected: " + expected()) +
  185. //                (actual() == "" ? "" : "\nactual: " + actual()));
  186. //    }
  187. /*
  188.     а вот это - зря закомментила)
  189.  
  190.     ну да, тут у нас нету локатора)
  191.     но
  192.     у нас есть entity
  193.     если у всех классов, имплементирующих LazyEntity - будет нормально реализованнй метод toString()
  194.     то и наша эта фраза будет ок - мы рсто будем использовать вместо locator - entity
  195.  
  196. */
  197. ********************************************
  198. public class LazyCollection implements LazyCollectionEntity {
  199. public class LazyElement implements LazyElementEntity {
  200. /*
  201.     тут в toString() - можно вернуть просто - locator.toString();
  202. */
  203. **************************************************
  204. /*
  205.  
  206.     следующий наворот )
  207.  
  208.  
  209.     WebElement - это тоже интерфейс
  210.  
  211.     Если мы отнаследуем наш интерфейс LazyElement от WebElement
  212.     Это то же самое что и заявить - "наш LazyElement - полная замена WebElement - и везде где вы его использовали
  213.     вы теперь можете использовать наш лейзи враппер
  214.     который помимо всех фич вебэлемента еще и будет ждать себя..."
  215.  
  216.     конечно, можно было бы абстрактный класс реализовать имплементирующим два интерфейса
  217.     Класс может быть реализован от нескольких интерфейсов
  218.  
  219.     но тогда, при использовании переменной типа LazyElement - мы не получим функциональности WebElement
  220.  
  221.     потому тут правильнее именно отнаследовать LazyElement от WebElement
  222.  
  223.     Это в java-ООП мире достаточно прикольная практика -
  224.     всегда, когда ты хочешь сделать какие-то штуки внутри объекта публичными -
  225.     выносить их сначала в отдельный интерфейс - и потом его имплементировать
  226.  
  227.     потому что просто сделать какие-то штуки публичными - это недостаточно "строго"
  228.  
  229.     если ты четко заявляешь - мой объект поддерживает такие-то интерфейсы, тогда
  230.     все могут общаться с твоим объектом через четко прописанное API этого интерфейса
  231.  
  232.     тут надо внимательно к вопросу подойти)
  233.  
  234.     в рамках LazyElement - не реализовывай методов, одноименных с методами WebElement
  235.  
  236.     да, мы для некоторых методов потерям chainable возможности
  237.  
  238.     но зато не будет двусмысленностей
  239.  
  240.     в абстрактном классе AbstractLazyElement - реализуй все вебэлементовские методы
  241.     думаю, проблем с этим не будет
  242.  
  243.     думай - в каких методах и чего надо ждать - ничего не ждать / ждать видимости / ждать наличия в DOM
  244.  
  245. */
  246.  
  247. **********************
  248.  
  249. /*
  250.     следующий наворот )
  251.  
  252.     наворачиваем Collection )
  253.  
  254.         наследуем этот интерфейс и от Iterable<LazyElement>
  255.  
  256.         цель - уметь писать такой код
  257.  
  258.         elements = $$(...);
  259.         for(LazyElement element:elements) {
  260.             ...
  261.         }
  262.  
  263.         т е уметь обходить нашу коллекцию элементов в таком варианте цикла
  264.  
  265.         чистая теория
  266.         http://tutorials.jenkov.com/java-generics/implementing-iterable.html
  267.  
  268.         нам она практически не пригодится )
  269.         просто для понимания - разумно ознакомиться
  270.  
  271.         достаточно понять, что
  272.         при имплементировании интерфейса Iterable<...>
  273.         надо будет реализовать метод
  274.          public Iterator<ProxyElement> iterator()
  275.  
  276.         Дальше мы схитрим)
  277.  
  278.         List<...> тоже наследник Iterable<...>
  279.  
  280.         если мы внутри метода iterator()
  281.             создадим и заполним список list типа List<LazyElement> элементами из коллекции
  282.  
  283.             то тогда можно вернуть в качестве результата метода iterator() - list.iterator();
  284.  
  285.         загвоздка в том, что в коллекции  getWrappedEntity()  возвращает значение типа List<WebElement>
  286.         а мы хотим получить List<LazyElement>
  287.  
  288.         Вот и пришло время создать еще одного потомка для AbstractLazyElement
  289.           назовем его LazyWrappedWebElement (обернутый веб элемент)
  290.           будем передавать ему в конструктор вебЭлемент
  291.           как ты понимаешь, его реазизация getWrappedEntity() - будет возвращать тот же веб элемент
  292.  
  293.         И теперь опять возвращаемся к методу iterator()
  294.         Если в новый список List<LazyElement>
  295.         Ты будешь складывать новосозданные объекты типа LazyWrappedWebElement
  296.         То это будет ОК (т к LazyWrappedWebElement - потомок абстрактного класса который имплементирует интерфейс LazyElement)
  297.  
  298.         Проверяем новую функциональность на коде типа
  299.  
  300.             for (LazyElement element:tasks) {
  301.                 System.out.println(element.getText());
  302.                 element.shouldHave(text("а"));
  303.             }
  304.  
  305. */
  306. **********************************
  307.  
  308. public abstract class AbstractCondition<V> implements Condition<V>{
  309.  
  310.     ...
  311.     public abstract String identity();
  312.     public abstract String expected();
  313.     public abstract String actual();
  314.  
  315. /*
  316.     ну и еще один наворот на тему интерфейсов )
  317.  
  318.     как выше писала - класс может имплементировать несколько интерфейсов
  319.  
  320.     и прикольно - всю функциональность описывать на уровне интерфейсов
  321.     это дает ряд интересных полезных эффектов
  322.  
  323.     вот тут например -
  324.     описать интерфейс DescribesResult
  325.     с методами identity(), expected() и  actual()
  326.  
  327.     и пусть класс AbstractCondition<V> имплементирует как Condition<V>, так и DescribesResult
  328.  
  329.     первая мелочь - можно описания абстрактных методов отсюда убрать
  330.     (они же и так объявлены в интерфейсе, а реализовывать мы будем в кондишенах уже)
  331.  
  332.     вторая приятная и важная вещь - соблюли лучше Single Responsibility Principle
  333.  
  334.     третья приятная вещь
  335.     конечно, при условии, если таки для переменных-кондишенов будем использовать типы интерфейсов
  336.     CollectionCondition & ElementCondition (выше описаннный вариант 1)
  337.     когда мы будем оперировать переменной
  338.         CollectionCondition condition
  339.         или
  340.         ElementCondition condition
  341.  
  342.     то для такой переменной - мы не сможем вызвать методы  identity() /  expected() /   actual()
  343.     т е - там, где это было нужно - у нас эта функциональность была видна
  344.     а там, где это не нужно - этого вообще не видно
  345. */
Advertisement
Add Comment
Please, Sign In to add comment