vendredi 24 juin 2016

Create isolated DDD domain model as a lib, to be used for any client

I would like to create a DDD domain model library, to be used to any client. Where each client will provide default implementation of services.

design

My solution is something mixing Factory Method Pattern with Singleton:

1. domain-model.lib: Project structure:

project estructure

1.1. domain-model.lib: Implementation:

User.class:

public class User {
    private String id;
    private String name;

    public String getId() {
            return id;
    }

    public void setId(String id) {
        this.id = id;
    }


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

UserRepository.class:

public class UserRepository {
    public User getUser(String id){
        return UserDAOAbstractFactory.getInstance().getDefaultImplementation().read(id);
    }

    public void saveUser(User user){
        UserDAOAbstractFactory.getInstance().getDefaultImplementation().insert(user);
    }
}

UserDAO.class:

public interface UserDAO {
    User read(String id);
    void insert(User user);
    void update(User user);
    void delete(User user);
}

UserDAOAbstractFactory.class:

public abstract class UserDAOAbstractFactory implements Factory<UserDAO> {
    private static UserDAOAbstractFactory instance;

    public static UserDAOAbstractFactory getInstance() {
        if(instance == null){
            synchronized (UserDAOAbstractFactory.class) {
                if(instance == null) {
                    throw new IllegalStateException("Cannot call getInstance() method before calling build() method");
                }
            }
        }
        return instance;
    }

    public static <T extends UserDAOAbstractFactory> void build(Class<T> clazz) {
        if(instance == null){
            synchronized (UserDAOAbstractFactory.class) {
                if(instance == null) {
                    try {
                        instance = clazz.newInstance();
                    } catch (InstantiationException | IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
                else{
                    throw new IllegalStateException("Factory already built. Cannot build twice.");
                }
            }
        }
        else{
            throw new IllegalStateException("Factory already built. Cannot build twice.");
        }
    }
}

Factory.class:

public interface Factory<T> {
    T getDefaultImplementation();
}

2. "Application 1" - Project structure:

project structure- application 1

2.2 "Application 1" - Implementation:

UserDAOFactoryMock.class

public class UserDAOFactoryMock extends UserDAOAbstractFactory {
    private UserDAO userDAOMock = new UserDAO() {
        final String USER_ID = "123";
        User user;

        @Override
        public User read(String id) {
            if(user.getId().equals(USER_ID)){
                return user;
            }
            return null;
        }

        @Override
        public void insert(User user) {
            this.user = user;
            this.user.setId(USER_ID);
        }

        @Override
        public void update(User user) {
            throw new UnsupportedOperationException();
        }

        @Override
        public void delete(User user) {
            throw new UnsupportedOperationException();
        }
    };

    @Override
    public UserDAO getDefaultImplementation() {
        return userDAOMock;
    }
}

UserDAOFactoryTest.class

public class UserDAOFactoryTest {

    public UserDAOFactoryTest(){
        UserDAOAbstractFactory.build(UserDAOFactoryMock.class);
    }

    @Test
    public void insertReadUser_expectOK(){
        User user = new User();
        user.setName("Paulo");

        UserRepository userRepository = new UserRepository();

        // Insert User
        userRepository.saveUser(user);
        String userId = user.getId();

        // Read user
        User returnedUser = userRepository.getUser(userId);

        // Check
        assertTrue(user.getId().equals(returnedUser.getId()));
        assertTrue(user.getName().equals(returnedUser.getName()));
    }
}

My concern is, it is a good approach to use with the team? There is some anti-pattern?

Aucun commentaire:

Enregistrer un commentaire