вторник, 28 марта 2017 г.

Функциональное программирование в Java 8 (Часть 1): Функция как объект

После прочтения Части 0 вы поняли, что функциональное программирование - это круто, сегодня мы сделаем наш первый большой шаг в данной теме. С выходом Java 8 функции  стали функциями первого класса. А это значит, что вы можете передавать функцию как параметр другой функции, возвращать функцию и хранить функцию как объект.

Почему я должен хранить функцию как объект?

  1. Создавать "super private" функции. Как вы знаете, качество кода очень важно. По этому мы используем private функции, чтобы снизить число открытых методов класса. Мы не хотим показывать основной код пользователям, им достаточно работать только с открытыми методами объекта. Но что, если мы хотим создать функцию, которая доступа только одному методу во всем классе? Если хранить функцию первого класса ,как объект, который будет доступен только одному методу, мы сможем этого добиться.
  2. Улучшить паттерны проектирования. Если вы когда-либо работали над большим проектом, то знаете, каким запутанным он может быть. По-этому были изобретены паттерны проектирования. Один из самых прикольных - паттерн стратегия. Я напишу подробный пост об этом позже, но основная мысль заключается в том, что он переключает похожие алгоритмы, в зависимости от параметра. Для каждого алгоритма необходимо написать свой класс, который имплементирует интерфейс. Но когда вы можете хранить функцию как объект, то вам нужна только одна функция-объект для каждого алгоритма. Это позволяет создавать меньше кода и делает его понятнее.
  3. Создавать функции "Высшего порядка". Теперь самое прикольное. Вы можете использовать каждый объект в качестве параметра метода. Почему бы не вызвать метод с аргументом функции? Методы, которые принимают функцию как параметр или возвращают ее, называются функциями более высокого порядка. Прежде чем я смогу привести вам пример, мы должны научиться хранить функцию в объекте.

Хранение функции в объекте.

В Java 8 был представлю интерфейс Interface Function<T,R>. Он может хранить функцию, которая принимает один аргумент и возвращает объект. Generic T является типом аргумента, а R - типом объекта, который вы возвращаете.

Пример: Функция вычисления.

Это очень простой пример функции высшего порядка. Он принимает функцию и Integer и вычисляет данную функцию с помощью Integer.

public static Integer compute(Function<Integer, Integer> function, Integer value) {
    return function.apply(value);
}
А теперь мы хотим использовать эту функцию, чтобы инвертировать число.
public class AwesomeClass {
    private static Integer invert(Integer value) {
        return -value;
    }
    public static Integer invertTheNumber(){
        Integer toInvert = 5;
        Function<Integer, Integer> invertFunction = AwesomeClass::invert;
        return compute(invertFunction, toInvert);
    }
    
}
Здесь два интересных момента, первый из них:
return function.apply(value);
Вызов метода объекта-функции, просто используются аргументы и возвращается результат метода. Для нашего примера необходимо написать:
return invert(value);
Второй интересный момент:
Function<Integer, Integer> invertFunction = AwesomeClass::invert;
То, что мы здесь используем называется ссылкой на метод. Мы делаем из метода invert() объект-функцию, используя оператор ::. Это один из двух способов хранить функцию, как объект. Но этот код ничего не упощает. Его можно изменить:
public class AwesomeClass {
    private static Integer invert(Integer value) {
        return -value;
    }
    public static Integer invertTheNumber(){
        Integer toInvert = 5;
        return invert(toInvert);
    }    
}
Такое решение не нуждается в функции compute, да и в самом ФП тоже. Чтобы сделать ФП подходящим в данном примере, нужно представить второй способ хранения функции как объект. Он опирается на анонимные функции или так называемые лямбды.

Как работать с лямбдами

Чтобы работать с лямбдами в Java 8 необходимо разобраться с новым синтаксисом, чтоб работать с ними (Лямбдами) правильно.

Пример: сложение двух Integer

В старой-доброй Java7 вы могли написать метод, чтобы сложить два числа:
public Integer add(Integer a, Integer b) {
    return a + b;
}
А это Java 8 c лямбдами:
BiFunction<Integer, Integer, Integer> add = (a, b) -> a + b;
Достаточно просто, не так ли? BiFunction - это еще один интерфейс из java.util, чтобы представить функцию с двумя входными параметрами и одним выходным.В скобках указываются входные параметры. Вы не обязаны указывать их тип. Необходимо только сказать сколько их будет и как они называются. В Java 7 это эквивалентно:
(Integer a, Integer b)
Следующее -> стрелка. Она соответствует фигурным скобочкам и отделяет голову функции от тела. После стрелки можно работать с входными параметрами. Если у функции всего одно вычисление - слово return не нужно, будет возвращен результат этого вычисления. Конечно, тело функции можно сделать больше, добавив фигурные скобки:
BiFunction<Integer, Integer, Integer> add = (a,b) -> {
    Integer result = a + b;
    return result;
};

Но чаще всего, нужна только одна строка, по-этому фигурные скобки и ключевое слово return не нужны.

Улучшение функции вычисления

Учитывая выше сказанное, можно провести рефакторинг:
public class AwesomeClass {
    public static Integer invertTheNumber(){
        Integer toInvert = 5;
        return compute((a) -> -a, toInvert);
    }
}
Вот это уже красивый код! Мы можем реализовать нашу функцию инвертирования через лямбды. Это делает наш код красивее, чем старая ФП версия и версия с Java7. Нам не нужно создавать дополнительные методы для инвертирования Integer, мы просто используем небольшую лямбду, которая все реализует.

Заключение

На сегодня все. Мы сделали первые крупные шаги в направлении ФП на Java 8. Прежде всего, мы увидели много преимуществ ФП. После этого мы использовали нашу первую функцию в качестве параметра в другом методе, используя ссылки на методы и лямбду (анонимные функции). Во второй части мы расскажем о Optionals и о том, как с ними работать.
 Спасибо за чтение и хорошего дня,
 Никлас

PS это мой перевод данной статьи

вторник, 21 марта 2017 г.

Функциональное программирование в Java 8(Часть 0): Мотивация

Что же такое функциональное программирование?


Возможно, вы слышали о функциональном программировании (ФП) и как сильно оно снижает LOC (строк кода - Lines Of Code) и улучшает читабельность кода. Но что в действительности значит программировать функционально и какие отличия от ООП.
  1. Все переменные final

  2.  public String greet(List<String> names) {
        String greeting = "Welcome ";
        for(String name : names) {
            greeting += name + " "; // We don't care about the last space right now.
        }
        greeting += "!";
        return greeting;
    }
    
    

    Это полностью валидная функция для создания строки приветствия в Java. Но если вы используете ФП, то такой способ не сработает. Вы изменяете состояние приветствия (greeting), что не разрешено в ФП. Если вы попытаетесь сделать final greeting, то получите ошибку. Всякий раз, когда вы используете += с String, значение меняется. Обычно в ФП вы конкатенируете все имена в одну строку:
    public String greet(List<String> names) {
        final String reducedString = "Welcome " + names.get(0) + " " + names.get(1) + " " + ...
                + names.get(names.size()-1) + " ";
        return reducedString + "!";
    }
    
    

    Если это решение вам кажется ужасным - вы правы. Но ФП может все исправить:
    public String greet(List<string> names) {
        String greeting = names
                .stream()
                .map(name -&gt; name + " ")
                .reduce("Welcome ",
                        (acc, name) -> acc + name);
        return greeting + "!";
    }
    

    Преимущество final переменных, что их значение всегда одинаковое. Это делает тестирование и дебаггинг намного проще.
  3. Не используйте глобальные пременные.
    Я выбрал пример с глобальным временем. Вы пишете static функцию, которая возвращает текущее время строкой. ООП версия может выглядеть так:
    public class Utils {
        private static Time time;
        public static String currTime() {
            return time.now().toString();
        }
    }
    

    Если вызвать currTime() дважды - результат будет разный, Хотя у нас один и тот же входной параметр(которого нет), результат разный.
    Это не может произойти в ФП. Каждый метод зависит только от своих собственных параметров и все. Т.е. если мы хотим это реализовать, то объект time должен быть входным параметром:
    public class Utils {
        public static String currTime(Time time) {
            return time.now().toString();
        }
    }
    
    Это может выглядеть странно для ООП, но у такого решения есть преимущества. Во-первых, такой код легче читать. Если вы знаете, что метод зависит только от своих параметров, вам не нужно искать глобальные паременные, которые добавляют магии в ваш метод. Во-вторых, такой когд лече тестировать.Когда вам нужно протестировать данный метод, вы можете просто замокировать объект Time. Для решения в ООП это сделать достаточно сложно.
  4. Используйте функции, как параметр.
    У ФП функция может быть аргументом другой функции. Разве это не круто? Предположим, что нам необходимо дабавить каждому элементу List 1. Вот пример релизации в ООП:
    public List<integer> addOne(List<integer> numbers) {
        List<integer> plusOne = new LinkedList&lt;&gt;();
        for(Integer number : numbers) {
            plusOne.add(number + 1);
        }
        return plusOne;
    }
    
    
    В итоге необходимо оперировать двумя списками. Что может привести к ошибкам. Так же существует шанс внести изменения в значения входного параметра, что может привести к дальнейшим проблемам. В ФП вы можете применить функцию map к каждому элементу списка и сохранить значение в другой список:
    public List<Integer> addOne(List<Integer> numbers) {
        return numbers
                .stream()
                .map(number -&gt; number + 1)
                .collect(Collectors.toList());
    }
    
    
    Это уменьшает количество переменных и, следовательно, места, где вы можете допустить ошибки. Вы создаете новый список и не измените числа во входном списке.

Заключение.


Надеюсь, вы заметили преимущества ФП. Позже вы научитесь по-настоящему ценить их. Final переменные - удобнее с точки зрения многопоточности, отсутствие глобальных переменных повышает тестируемость и функции, поскольку параметры улучшают качество кода. И не беспокойтесь, вначале вы можете смешивать ООП и ФП в своем коде. В следующей части мы поговорим о функциях как параметрах. Так же я представлю анонимные функции (lambdas) и ссылки на методы. Надеюсь, вам понравилось это краткое введение в большую тему функционального программирования. Пожалуйста, напишите мне, если что-то непонятно. Или есть ли какая-нибудь причина ненавидеть функциональное программирование? Я хотел бы обсудить эти темы с вами.


PS это мой перевод данной статьи

воскресенье, 19 марта 2017 г.

java Interface vs. Abstract

Предисловие


Классом называется класс, когда у него есть имя и реализованы все имеющиеся методы, которые объявлены во всей иерархии классов. Иерархия вместе с ее супертипом становятся более общим преставлением действующего  домена, и, наконец, выходят за пределы этой границы и заканчиваются тем фактом, что почти все является объектом(Очень странное предложение). Суперкласс может быть конкретным классом,  который, очевидно, не final или абстрактным классом,  или  даже одним или несколькими интерфейсами. Комбинирование супер-класса или абстрактоного класса с интерфейсами так же широко известный способ описания класса. Полиморфизм появляется, когда более чем один класс реализует определенный метод различно, в зависимости от назанчения класса. В этой статье рассматривается два из трех супертипов, выделены их основные харрактеристики.  Интерфейс и абстрактный класс могут быть созданые экземпляром анонимного класса.

Абстрактный класс


Обычно, абстрактный класс реализует общее поведение и переменные любого конкретного класса и его методы могут быть уже указаны в интерфейсе. Различимое поведение достигается через объявление абстрактных методов, которые необходимо реализовать в определенном классе.  Абстрактный класс может наследовать поведение от других абстрактных или конкретных классов и может обогащать дальнейшее поведение при добавлении интерфейса. В java такие реализации могут быть явно подчеркнуты с помощью аннотации Override, которая информирует об изменении. Полиморфизм останавливается в тот момент, когда реализация метода становится final. Методы в абстрактном классе могут быть private, это делает такой класс  более подходящим для инкапсуляции private методов, в то же время позволяя рабить  сложные методы на мелкие части. Абтрактный класс очень близок к конкретной реализации класса.

Интерфейс


C Java 1.8 интерфейсы могут реализовывать default методы, для обеспечения общего поведения. Следовательно и абстрактный класс и интерфейс  имеют свой подход, в отношении своих особенностей. Для переменных интерфейса явно указано, что они public и final, а у  переменных абстрактного класса могут быть различные модификаторы доступа. Более того, есть небольшая разница в возможности повлиять на модификатор доступа для default метода. Он всегда public, а у абстрактного класса, реализация может быть с любым доступом (public, protected, default, private). Все, что объявлено в интерфейсе, везде доступно  и может расширяться объектом со специфическим поведением. Интерфейс позволяет наследоваться только от другого интерфейса. И интерфейс и абстрактный класс могут реализовывать статические методы. Другой тип интерфейса  - интерфейс, который не декларирует ни одного метода и применяется как интерфейс-индикатор.Они просто указывают на договор с разработчиком, например, что класс клонируемый или сериализуемый.

Пример 1


Это сравнение подчеркивает преимущество абстрактного класса над интерфейсом, ориентированным на вычисление угла между двумя прямыми. Однако для этой цели можно использовать и интерфейс, и абстрактный класс, в то время как первый не согласуется с предложениями Мартина о чистом коде.
public interface TwoDimensional {
    double PI = 3.141579; //is public and final
    default double getAngle(TwoDimensional a, TwoDimensional b) /* is public */{
        double alpha = 0.0;
        //do complex calculation here
        //modulus
        //scalar
        //to degrees
        return alpha;
    }
    int getX(); //is public
    int getY();
}

public abstract class AbstractTwoDimensional {
    public final double PI = 3.141579;
    private int x;
    private int y;
    public final double getAngle(AbstractTwoDimensional other) {
        double a = calcModulus(x, y);
        double b = calcModulus(other.getX(), other.getY());
        double s = scalar(other.getX(), other.getY());
        return toDegrees(s, a, b);
    }
    private double toDegrees(double s, double a, double b) {
        //compute
        return 0;
    }
    private double calcModulus(int x, int y) {
        //compute...
        return 0;
    }
    private double scalar(int x2, int y2) {
        //compute...
        return 0;
    }
    abstract int getX();
    abstract int getY();
    //some other abstract methods…
}

Пример 2


Этот пример очень близок к предыдущему, но отличается сочетанием интерфейса и абстрактных классов. Оба они характеризуют конкретные классы.
public interface TwoDimensional {
    Double PI = 3.141579;
    double getAngle(TwoDimensional other);
    int getX();
    int getY();
}

public abstract class AbstractTwoDimensional implements TwoDimensional {    
    private int x;
    private int y;
    @Override
    public final double getAngle(TwoDimensional other) {
        double a = calcModulus(x, y);
        double b = calcModulus(other.getX(), other.getY());
        double s = scalar(other.getX(), other.getY());
        return toDegrees(s, a, b);
    }
    @Override
    public final int getX() {
        return x;
    }
    @Override
    public final int getY() {
        return y;
    }
    protected void setX(int x) {
        this.x = x;
    }
    protected void setY(int y) {
        this.y = y;
    }
    private double toDegrees(double s, double a, double b) {
        //compute
        return 0;
    }
    private double calcModulus(int x, int y) {
        //compute...
        return 0;
    }
    private double scalar(int x2, int y2) {
        //compute...
        return 0;
    }
}

public class MutableLine extends AbstractTwoDimensional {
    //some specific things…
    public MutableLine(ImmutableLine line) {
        //extract data and init
    }
}

public final class ImmutableLine extends AbstractTwoDimensional {
    //some specific things...
    public ImmutableLine(MutableLine line) {
        //extract data
    }
    @Override
    public final void setX(int x) {
        //throw an appropriate exception
    }
    @Override
    public final void setY(int y) {
        //throw an appropriate exception
    }
}
PS это мой перевод данной статьи

воскресенье, 12 марта 2017 г.

Sprig boot, Spring Data интеграция с JPA

Сейчас, интеграция Spring и JPA стало прстым и понятным благодаря Spring boot и Spring Data. Рассмотрим его. Так же используем Docker. Начнем с него.
Настроим PostgresSql:

docker pull postgres
#run the container
docker run --name postgreslocal -e POSTGRES_PASSWORD=postgres -d postgres
#get the ip
docker inspect --format '{{ .NetworkSettings.IPAddress }}' postgreslocal
#get the port
docker inspect --format '{{ .NetworkSettings.Ports }}' postgreslocal


Создадим таблицу работников (Employees)

create schema spring_data_jpa_example;

create table spring_data_jpa_example.employee(
    id  SERIAL PRIMARY KEY,
    firstname   TEXT    NOT NULL,
    lastname    TEXT    NOT NULL,  
    email       TEXT    not null,
    age         INT     NOT NULL,
    salary         real,
    unique(email)
);
 
insert into spring_data_jpa_example.employee (firstname,lastname,email,age,salary)
values ('Emmanouil','Gkatziouras','gkatzioura@gmail.com',18,3000.23);


Далее gradle-файл
group 'com.gkatzioura'
version '1.0-SNAPSHOT'

apply plugin: 'java'
 
sourceCompatibility = 1.8

buildscript {

    repositories {
       mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:1.3.3.RELEASE")
    }
}
 
apply plugin: 'idea'
apply plugin: 'spring-boot'
 
repositories {
    mavenCentral()
}
 
dependencies {
    compile("org.springframework.boot:spring-boot-starter-web") {
        exclude module: "spring-boot-starter-tomcat"
    }
    compile("org.postgresql:postgresql:9.4-1206-jdbc42")
    compile("org.springframework.boot:spring-boot-starter-jetty")
    compile("org.springframework.boot:spring-boot-starter-data-jpa:1.3.3.RELEASE")
    compile("com.mchange:c3p0:0.9.5.2")
    testCompile("junit:junit:4.11");
}

Обратите внимание, мы добавили пул соединений с3p0, spring-boot-starter-data-jpa для Hibernate  и драйвер для Postgress. Это все, что нам нужно.

Класс Application:
package com.gkatzioura.springdata.jpa;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
 
/**
 * Created by gkatzioura on 6/2/16.
 */
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
 
        SpringApplication springApplication = new SpringApplication();
        ApplicationContext ctx = springApplication.run(Application.class, args);
    }

}

Конфигурация Datasource:
package com.gkatzioura.springdata.jpa.config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
import javax.sql.DataSource;
/**
 * Created by gkatzioura on 6/2/16.
 */
@Configuration
public class DataSourceConfig {
 
    @Bean
    public DataSource createDataSource() throws Exception {
 
        ComboPooledDataSource ds = new ComboPooledDataSource();
        ds.setJdbcUrl("jdbc:postgresql://172.17.0.3:5432/postgres?user=postgres&password=postgres");
        ds.setDriverClass("org.postgresql.Driver");
 
        return ds;
    }
 
}

Конфигурация JPA:
package com.gkatzioura.springdata.jpa.config;
 
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
 
import javax.sql.DataSource;
import java.util.Properties;
 
/**
 * Created by gkatzioura on 6/2/16.
 */

@Configuration
@EnableJpaRepositories(entityManagerFactoryRef = "entityManagerFactory",
        transactionManagerRef = "transactionManager",
        basePackages = {"com.gkatzioura.springdata.jpa.persistence"})
@EnableTransactionManagement
public class JPAConfig {
 
    @Autowired
    private DataSource dataSource;
 
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
 
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setDataSource(dataSource);
        entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
        entityManagerFactoryBean.setJpaProperties(hibernateProperties());
        entityManagerFactoryBean.setPackagesToScan(new String[] {"com.gkatzioura.springdata.jpa.persistence"});
        return entityManagerFactoryBean;
    }
 
    @Bean
    public JpaTransactionManager transactionManager() {
 
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
        return transactionManager;
    }
 
    private Properties hibernateProperties() {
 
        Properties properties = new Properties();
        properties.put("hibernate.dialect","org.hibernate.dialect.PostgreSQL9Dialect");
        properties.put("hibernate.globally_quoted_identifiers","true");
 
       return properties;
    }
}


Наша сущность для таблицы работников
package com.gkatzioura.springdata.jpa.persistence.entity;
 
import javax.persistence.*;

/**
 * Created by gkatzioura on 6/2/16.
 */
@Entity
@Table(name = "employee", schema="spring_data_jpa_example")
public class Employee {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;
 
    @Column(name = "firstname")
    private String firstName;
 
    @Column(name = "lastname")
    private String lastname;
 
    @Column(name = "email")
    private String email;
 
    @Column(name = "age")
    private Integer age;
 

    @Column(name = "salary")
    private Integer salary;
 
    public Long getId() {
        return id;
    }
 
    public void setId(Long id) {
        this.id = id;
    }
 
    public String getFirstName() {
        return firstName;
    }
 
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
 
    public String getLastname() {
        return lastname;
    }
 
    public void setLastname(String lastname) {
        this.lastname = lastname;
    }
 
    public String getEmail() {
        return email;
    }
 
    public void setEmail(String email) {
        this.email = email;
    }
 
    public Integer getAge() {
        return age;
    }
 
    public void setAge(Integer age) {
        this.age = age;
    }
 
    public Integer getSalary() {
        return salary;
    }
 
    public void setSalary(Integer salary) {
        this.salary = salary;
    }
}
Репозиторий, который поможет нам выбрать всех работников
package com.gkatzioura.springdata.jpa.persistence.repository;
 
import com.gkatzioura.springdata.jpa.persistence.entity.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
 
/**
 * Created by gkatzioura on 6/2/16.
 */
@Repository

public interface EmployeeRepository extends JpaRepository{
}
И сам контроллер,который будет получать данные
package com.gkatzioura.springdata.jpa.controller;
 
import com.gkatzioura.springdata.jpa.persistence.entity.Employee;
import com.gkatzioura.springdata.jpa.persistence.repository.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
import java.util.List;
 
/**
 * Created by gkatzioura on 6/2/16.
 */
@RestController
public class TestController {
 
    @Autowired
    private EmployeeRepository employeeRepository;
 
    @RequestMapping("/employee")
    public List getTest() {
 
        return employeeRepository.findAll();
    }
}
Очень удобно, все зависимости и другие xml-конфигурации остались в прошлом.
Весь код можно найти здесь


PS это мой перевод данной статьи.

понедельник, 6 марта 2017 г.

Spring Dependency Lookup

Рассмотрим способ внедрения зависимостей через DependencyLookup. Предположим, нам необходимо получать новый инстанс объекта при каждом обращении. С этим поможет справится DependencyLookup. Способ реализации через аннотации. ApplicationContext будет практически пустой:

    

Интерфейс бина в котором необходим постоянно обновляемый бин:
package com.test.example;

public interface DemoBean {
    MyHelper getMyHelper();
    void someOperation();
}


Релизация постоянно обновляемого бина:
package com.test.example;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Component
@Scope("prototype")
public class MyHelper {
    public void doSomethingUsefully(){

    }
}

Самое интересное это @Scope("prototype"). Данная аннотация говорит Spring, что, данный бин не синглтон. Реализация бина в который внедряется зависимость:

package com.test.example;

import org.springframework.beans.factory.annotation.Lookup;
import org.springframework.stereotype.Component;

@Component
public class AbstractLookupDemoBean implements DemoBean{

    @Lookup
    public MyHelper getMyHelper(){
        return null;
    }

    public void someOperation() {
        getMyHelper().doSomethingUsefully();
    }
}

Аннотация @Lookup говорит, о том, что Spring'у необходимо будет взят данную функцию и предоставить свою реализацию с уже внедренной зависимостью, т.е. можно было бы сделать данный класс абстрактным и  сделать так:
@Lookup
public abstract MyHelper getMyHelper();

Работоспособность бы не изменилась. Ну и класс запуска:
package com.test.example;

import org.springframework.context.support.GenericXmlApplicationContext;

public class Application {
    public static void main(String[] arg){
        GenericXmlApplicationContext context = new GenericXmlApplicationContext();
        context.load("application.xml");
        context.refresh();

        DemoBean demoBean = (DemoBean) context.getBean("abstractLookupDemoBean");
        demoBean.someOperation();
        MyHelper helper1 = demoBean.getMyHelper();
        MyHelper helper2 = demoBean.getMyHelper();
        System.out.println("Helper Instances the Same?: " + (helper1 == helper2));
    }
}

В консоли всегда будет false
Теперь рассмотрим реализацию через xml. Все аннотации будут удалены, Контекст будет


    
    
        
    


Классы не изменятся, в них только пропадут аннотации.

четверг, 2 марта 2017 г.

Модальные глаголы


Модальные глаголы - это вспомогательные глаголы, которые выражают возможность, вероятность, необходимость того или иного действия.
К модальным глаголам относятся: can, could, may, might, must, will, would, shall, should, ought to.
Основные характеристики:

  1. Модальные глаголы не имеют окончания -s  в единственном числе. She must go to work every day.
  2. Модальные глаголы не изменяются по временам. She can go with us. (Она сможет пойти с нами). You must keep it a secret. (Ты должен держать это в секрете.)
  3. Модальные глаголы сами формируют вопросительную или отрецательную форму. May I use your phone? Tim shouldn't smoke so much.
  4. После модальных глаголов никогда не идет to. He may know about it.

Can

Can выражает способность или возможность выполнять действие и переводится как "могу, умею".
Используется:
  1. Для отражения физической или умственной способности. Can I borrow your pen, please?
  2. Для обозначения общей возможности/способности: Sally thinks her sister can be anywhere right now.
  3. Для того, чтобы попросить/дать разрешения. Can I come in?
  4. Для запрещения чего либо. You can’t use your cell phone here.
  5. Для выражения сильного недоверия, удивления в отрицательных (can’t) и вопросительных предложениях (Сan….?). Сan’t... переводится выражениями: не может быть; не может быть, чтобы; невероятно. Can… переводится выражением: Неужели….?Can/can’t + глагол выражает действие, относящееся к настоящему. He cannot be there! Он не может там быть! Can/can’t + Present Perfect выражает действие, относящееся к прошлому. Can you have seen this film? Неужели ты видел этот фильм?
  6. С глаголами see, hear, feel, smell, taste при условии, что действие происходит в настоящий момент (now). В этом случае can на русский язык не переводится. I can smell something burning. Я чувствую, что что-то горит.
Чтобы образовать предложение с CAN необзодимо воспользоваться схемой:

Местоимение/Существительное + Модальный глагол + Глагол без to + Остальные слова

Наречия never, seldom, often, usually, always стоят после can.
He can always answer the question

Наречия once a month, four times a year и т.д. ставятся в конце предложения.
Jessica can go to the museum twice a week.

Чтобы составить общий вопрос, глагол can необходимо поместить в начало предложения.
Can Sara go to London?
Вопросительное слово ставиться перед вспомогательным глаголом can.
When can they come?

Образование отрецания с can:

Местоимение/существительное +  модальный глагол + not + глагол без to + остальные слова

Можно использовать полную форму cannot(без пробела) или сокращенную can't
George cannot understand the rule.

Could

В прошедшем времени у глагола CAN есть форма COULD, переводится как мог, имел возможность
I could hear something. Я мог что-то расслышать.
Образуется:

Местоимение/Существительное + Модальный глагол + Глагол без to + остальные слова

Вопрос:

Модальный глагол + Местоимение/Существительное + Глагол без to + остальные слова


Отрицание

Местоимение/Существительное + Модальный глагол +not+ Глагол без to + остальные слова

Использование:
  1. В качестве формы can в прошедшем времени
  2. В настоящем и будущем времени с частицей БЫ, мог бы
  3. В сочетании с Present Perfect(have done), чтобы сказать о том, что могло бы произойти но не произошло по отношению к прошлому. I didn’t know that you wanted to go to the cinema. I could have got you a ticket. Я не знал, что ты хотел пойти в кино. Я мог бы купить тебе билет.
  4. В сочетании с Present Perfect(have done),чтобы сказать о том, что было бы невозможно по отношению к прошлому. It wasn’t true. She couldn't have said that. Это было неправдой. Не может быть, чтобы она сказала это.
  5. В сочетании с Present Perfect(have done) в вопросительном предложении, чтобы выразить сильное сомнение, недоверие по отношению к прошлому. Could they have left yesterday? Неужели они уехали вчера?

Be able to

Употребление
  1. Заменяет can в будущем времени, переводится как смочь. I’ll be able to speak Spanish fluently by the end of the year.
  2. Так же употребляется в прошедшем времени в утвердительной форме, когда идет речь о конкретном событии. Jim and Pete had a game of tennis yesterday. Pete played very well, but Jim was able to beat him. Джим и Пит играли в теннис вчера. Пит играл очень хорошо, но Джим смог его победить.
  3. can нельзя употреблять в будущем времени для обозначения физической или умственной возможности/способности, для этого мы употребляем оборот be able to: He will be able to walk in two days.