вторник, 2 декабря 2014 г.

Domain Design : Repository Implementation

Реализация репозитория 


import java.util.HashMap;
import java.util.Map;

/**
 * Для инстационирования и временного сохранения репозитория
 * @author oleksandr.zakharov
 */
public final class RepositoryFactory {

    private Repository repository;
    
    private static Map<String,Repository> repositoryMap = new HashMap<String,Repository>();
    
    private RepositoryFactory(){
        repository = new Repository();
    }
    
    public static RepositoryFactory createRepository(){
        RepositoryFactory repositoryFactory = new RepositoryFactory();  
        return repositoryFactory;
    }
    
    public RepositoryFactory addName(String name){
        repository.setName(name);
        return this;
    }
    
    public RepositoryFactory addSpecification(Specification s){
        repository.getSpecifications().add(s);
        return this;
    }
    
    public static Repository findRepository(String name){
        return repositoryMap.get(name);
    }
    
    public Repository buildAll(){
        repositoryMap.put(repository.getName(), repository);
        return repository;
    }
    
}



Определяем спецификацию репозитория

package repository;

/**
 *
 * @author oleksandr.zakharov
 */
public interface Specification {
    
    boolean validate(IEntity entity);
    
}

Сам репозиторий со спецификациями

package repository;

import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author oleksandr.zakharov
 * @param <T>
 */
public class Repository<T extends IEntity> {

    public Repository() {
        ts = new ArrayList<>();
        specifications = new ArrayList<>();
    }
    
    private boolean validate(IEntity entity){
        for(Specification s: specifications){
            if(!s.validate(entity)) return false;
        }
        return true;
    }
    
    private String name;
    
    private List<Specification> specifications;
    
    private List<T> ts; 

    List<Specification> getSpecifications() {
        return specifications;
    }

    String getName() {
        return name;
    }

    void setName(String name) {
        this.name = name;
    }
    
    public boolean save(T entity){
        if(validate(entity)){
            ts.add(entity);
            return true;
        }
        return false;
    }
}


интерфейс сущности 


package repository;

/**
 *
 * @author oleksandr.zakharov
 */
public interface IEntity {
    
    Long getId();
    
}

Небольшая реализация(счет продукта не должен быть больше 40)


package repository.impl;

import repository.IEntity;
import repository.Specification;

/**
 *
 * @author oleksandr.zakharov
 */
public class AmountSpec implements Specification{

    @Override
    public boolean validate(IEntity entity) {
        Product p = (Product) entity;
        return p.getAmount() > 40;
    }        
}


package repository.impl;

import repository.IEntity;

/**
 *
 * @author oleksandr.zakharov
 */
public class Product implements IEntity{
    
    private Long id;
    
    private double amount;

    @Override
    public Long getId() {
        return id;
    }

    public double getAmount() {
        return amount;
    }

    public void setAmount(double amount) {
        this.amount = amount;
    }
    
}


package repository.impl;

import repository.Repository;
import repository.RepositoryFactory;

/**
 *
 * @author oleksandr.zakharov Simple example
 */
public class TestMain {

    public static void main(String[] str) {
        RepositoryFactory
                .createRepository()
                .addName("Repository")
                .addSpecification(new AmountSpec()) // i added for specific repository
                .buildAll();
        Repository r = RepositoryFactory.findRepository("Repository");
        Product product = new Product();
        product.setAmount(40);
        System.out.print(r.save(product)); // если меньше сорока не сохраниться

    }

}

Domain Design: Repository

Репозиторий

Обзор
Данная статья посвящена рассмотрению репозитория(Repository). В статье приведено небольшое математическое обоснование репозитория.

Что понимается под репозиторием? До недавнего времени многие разработчики пользовались таким понятием как DAO. На самом деле это уместное название способа работы с персистентными сущностями, так как никакие действия больше над сущностями не производились кроме как CRUD операций, при этом мы полагали что сущности, которые мы изменяем уже находятся в состоянии соответствии нашей бизнес модели. В итоге мы получали то, что некий сервис инкапсулировал в себе все свойства системы такие как валидания, расчеты, при все этом он еще был и внешним API системы. Но возникает вопрос: почему внешний сервис  должен все делать. Допустим что это его основные функции, но проблема возникает тогда когда начинает расти сложность бизнес логики и конечно часто меняющиеся требования... 
Репозиторий(repository) - это хранилище бизнес логики. Репозиторий обладает следующим свойством: данные которые в него попадают всегда должны соответствовать бизнес требованиям. Приведу небольшой математический аппарат для этого утверждения:

Пусть имеется некоторый репозиторий R. В данный репозиторий можно добавлять, удалять, изменять некоторую бизнес модель. В простом случае это некоторая сущность E(entity). Для того чтобы добавить в репозиторий некоторую сущность(E) необходимо проверить соответствует ли она нашей бизнес модели(требованиям). Пусть KFn(E)
- это соответствие n-бизнес требованию для сущности E в репозитории R. На самом деле  fn - это сложная бизнес функция проверки нашей сущности. В общем случае это F = F1 + F2+F3 + … + F где Fn - функция проверки на соответствие конкретным требованиям.
K= принимает два значения 1 или 0;
Емкость репозитория задается функцией:
то есть сущность попадает в репозиторий, если она соответствует бизнес требованиям. Если включаются новые бизнес требования, тогда можно специфицировать репозиторий для хранения новой бизнес логики или исключать обьекты которые уже не соответствуют вновь поступившим требованиям.

Продолжение следует...