REFACTORING CODE
DOMAIN DRIVEN DESIGN WAY
Supported By:
Supported By:
I’M ANDI PANGERAN
@andi_pangeran
cybercoding.wordpress.com
Supported By:
AGENDA
 PRACTICE HOW TO REFACTORING CODE BASED ON DOMAIN
DRIVEN DESIGN MINDSET
 PRACTICE HOW TO WRITE UNIT TESTING
Supported By:
JOKO
Individual who has significant expertise in the
domain of the system being developed.
DOMAIN EXPERT
MEET OUR ACTOR
Supported By:
BENTO
Individual who has spend all of his life for coding.
PROGRAMMER
MEET OUR ACTOR
Supported By:
PRACTICE
Supported By:
Protect your invariants
REFACTORING
Supported By:
JOKO
PRACTICE
“A customer must
always have an
email address.”
Supported By:
PRACTICE
BENTO
public class Customer {
private String email;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
Supported By:
PRACTICE
BENTO
public class CostumerTest {
@Test
public void should_always_have_an_email() {
Customer customer = new Customer();
assertEquals(customer.getEmail(), "andi.pangeran@jtravl.com");
}
}
TEST FAIL
Supported By:
PRACTICE
BENTO
public class CostumerTest {
@Test
public void should_always_have_an_email() {
Customer customer = new Customer();
customer.setEmail("andi.pangeran@jtravl.com");
assertEquals(customer.getEmail(), "andi.pangeran@jtravl.com");
}
}
TEST PASSED
Supported By:
PRACTICE
BENTO
public class Customer {
private String email;
public Customer(String email) {
this.email = email;
}
}
Supported By:
PRACTICE
BENTO
public class CostumerTest {
@Test
public void should_always_have_an_email() {
Customer customer = new Customer("andi.pangeran@jtravl.com");
assertEquals(customer.getEmail(), "andi.pangeran@jtravl.com");
}
}
TEST PASSED
Supported By:
Use object as concistency boundaries
REFACTORING
Supported By:
JOKO
PRACTICE
“later prospective customer can be
upgraded to paying customer“
“Paying customer must have phone
number”
“we have two type of customer,
prospective and paying customer.”
Supported By:
PRACTICE
BENTO
public class ProspectiveCustomer extends Customer {
/* other attribute */
}
public class PayingCustomer extends Customer {
/* other attribute */
private String phone;
public PayingCustomer(String email, String phone) {
super(email);
this.phone = phone;
}
}
Supported By:
PRACTICE
BENTO
@Test
public void upgraded_prospective_paying() {
ProspectiveCustomer pcustomer = new
ProspectiveCustomer("andi.pangeran@jtravl.com");
assertEquals(pcustomer.getEmail(), "andi.pangeran@jtravl.com");
PayingCustomer payCustomer =
new PayingCustomer(pcustomer.getName(), “0852xxx”);
assertEquals(payCustomer.getEmail(), "andi.pangeran@jtravl.com");
assertEquals(payCustomer.getPhone(), " 0852xxx");
}
TEST FAIL
Supported By:
PRACTICE
BENTO
@Test
public void upgraded_prospective_paying() {
ProspectiveCustomer pcustomer = new
ProspectiveCustomer("andi.pangeran@jtravl.com");
assertEquals(pcustomer.getEmail(), "andi.pangeran@jtravl.com");
PayingCustomer payCustomer =
new PayingCustomer(pcustomer.getEmail(), “0852xxx”);
assertEquals(payCustomer.getEmail(), "andi.pangeran@jtravl.com");
assertEquals(payCustomer.getPhone(), " 0852xxx");
}
TEST PASSED
Supported By:
PRACTICE
BENTO
public class ProspectiveCustomer extends Customer {
/* other attribute */
public PayingCustomer upgradeToPayingCustomer(String phone) {
return new PayingCustomer(this.email, phone);
}
}
public class PayingCustomer extends Customer {
/* other attribute */
private String phone;
public PayingCustomer(String email, String phone) {
super(email);
this.phone = phone;
}
}
Supported By:
PRACTICE
BENTO
@Test
public void upgraded_prospective_paying() {
ProspectiveCustomer pcustomer = new
ProspectiveCustomer("andi.pangeran@jtravl.com");
assertEquals(pcustomer.getEmail(), "andi.pangeran@jtravl.com");
PayingCustomer payCustomer = pcostumer.upgradeToPaying(“0852xxx”);
assertEquals(payCustomer.getEmail(), "andi.pangeran@jtravl.com");
assertEquals(payCustomer.getPhone(), " 0852xxx");
}
TEST PASSED
Supported By:
JOKO
PRACTICE
“Paying customer must always have a
valid phone number”
Supported By:
PRACTICE
BENTO
@Test
public void upgraded_prospective_paying() {
PayingCustomer payCustomer =
new PayingCustomer(“test@mail.com", “badphonenumber”);
exception.expect(IllegalArgumentException.class);
}
TEST FAIL
Supported By:
PRACTICE
BENTO
public class PayingCustomer extends Customer {
/* other attribute */
private String phone;
public PayingCustomer(String email, String phone) {
super(email);
if (/* validation stuff of phone*/ ) {
throw new IllegalArgumentException();
}
this.phone = phone;
}
}
TEST PASSED
Supported By:
PRACTICE
BENTO
public class PayingCustomer extends Customer {
/* other attribute */
private String phone;
public PayingCustomer(String email, String phone) {
super(email);
if (/* validation stuff of phone*/ ) {
throw new IllegalArgumentException();
}
this.phone = phone;
}
}
TEST PASSED
Supported By:
Encapulate state and behavior with
value object
REFACTORING
Supported By:
PRACTICE
 Intro to value object
 Intro to immutable object
Supported By:
PRACTICE
BENTO
public class PhoneNumber {
private final String phone;
public PhoneNumber(String phone) {
if (/* validation stuff of phone*/ ) {
throw new IllegalArgumentException();
}
this.phone = phone;
}
public String getPhone() {
{
return this.phone;
}
}
Supported By:
PRACTICE
BENTO
public class PayingCustomer extends Customer {
/* other attribute */
private PhoneNumber phone;
public PayingCustomer(String email, PhoneNumber phone) {
super(email);
this.phone = phone;
}
}
TEST PASSED
Supported By:
PRACTICE
BENTO
@Test
public void upgraded_prospective_paying() {
PayingCustomer payCustomer =
new PayingCustomer(“test@mail.com", new
PhoneNumber(“badphonenumber”));
exception.expect(IllegalArgumentException.class);
}
TEST PASSED
Supported By:
Encapulate Operations
REFACTORING
Supported By:
JOKO
PRACTICE
“a Customer orders product and pays for
them”
Supported By:
Service.create
BENTO
Order order = new Order();
order.setCustomer(customer);
order.setProducts(products);
order.setStatus(PAYMENTSTATUS.UNPAID);
order.setPaidAmount(500);
order.setPaidCurrency(CURRENCY.IDR);
order.setStatus(PAYMENTSTATUS.PAID);
PRACTICE
Service.pay
Supported By:
Service.create
BENTO
Order order = new Order();
order.setCustomer(customer);
order.setProducts(products);
order.setStatus(new PaymentStatus(PAYMENTSTATUS.UNPAID));
order.setPaidAmount(500);
order.setPaidCurrency(CURRENCY.IDR);
order.setStatus(new PaymentStatus(PAYMENTSTATUS.PAID));
PRACTICE
Service.pay
Supported By:
Service.create
BENTO
Order order = new Order();
order.setCustomer(customer);
order.setProducts(products);
order.setStatus(new PaymentStatus(PAYMENTSTATUS.UNPAID));
order.setPaidMonetary(new Money(500, CURRENCY.IDR));
order.setStatus(new PaymentStatus(PAYMENTSTATUS.PAID));
PRACTICE
Service.pay
Supported By:
Service.create
BENTO
Order order = new Order(customer, products);
//set payment status in order constructor
order.setPaidMonetary(new Money(500, CURRENCY.IDR));
order.setStatus(new PaymentStatus(PAYMENTSTATUS.PAID));
PRACTICE
Service.pay
Supported By:
Service.create
BENTO
Order order = new Order(customer, products);
//set payment status in order constructor
order.pay (new Money(500, CURRENCY.IDR));
//set payment status in pay procedure
PRACTICE
Service.pay
Supported By:
Use Spefication
REFACTORING
Supported By:
JOKO
PRACTICE
“premium customers get special offers”
Supported By:
Service.premium
BENTO
If (customer.isPremium()) {
//send offer
}
PRACTICE
Supported By:
JOKO
PRACTICE
“order 3 times to become premium
customer”
Supported By:
Specification Interface
BENTO
public interface Specification<T> {
boolean isSatisfiedBy(T t);
Class<T> getType();
}
PRACTICE
Specification Abstract
abstract public class AbstractSpecification<T> implements
Specification<T> {
@Override
public boolean isSatisfiedBy(T t) {
throw new NotImplementedException();
}
/othercode
}
Supported By:
BENTO
public class CustomerIsPremium extends
AbstractSpecification<Customer> {
private OrderRepository orderRepository
public CustomerIsPremium(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
@Override
public boolean isSatisfiedBy(Customer customer) {
int count =
this.orderRepository.countByCustomer(customer.getId);
return (count > 3);
}
}
PRACTICE
Supported By:
PRACTICE
BENTO
@Test
public void specification_customer_premium() {
CustomerIsPremium<Customer> spec= new CustomerIsPremium();
customer2order = …
customer3order = …
assertFalse(spec.isSatisfiedBy(customer2order));
assertTrue(spec.isSatisfiedBy(customer3order));
}
TEST PASSED
Supported By:
JOKO
PRACTICE
“different rules apply for different
tenants.”
Supported By:
BENTO
public class CustomerWith3OrdersIsPremium implement
CustomerIsPremium {}
public class CustomerWith500kPremium implement
CustomerIsPremium {}
public class CustomerWithSpecialRequiredmentPremium
implement CustomerIsPremium {}
PRACTICE
Specification Interface
public interface CustomerIsPremium extends
Specification<Customer> {
boolean isSatisfiedBy(Customer cust);
}
Supported By:
BENTO
PRACTICE
public class SpecialOfferSender {
private CustomerIsPremium premiumSpec
public SpecialOfferSende(CustomerIsPremium premiumSpec) {
this.orderRepository = orderRepository;
}
public void sendOffersTo(Customer customer) {
if (this.premiumSpec.isSatisfiedBy(customer)) {
//send offers
}
}
}
Supported By:
Use Spefication for Object Selection
REFACTORING
Supported By:
JOKO
PRACTICE
“get a list of all premium customers”
Supported By:
PRACTICE
 Intro to predicate pattern
 Collection predicate
 JPA predicate
Supported By:
BENTO
PRACTICE
Specification Interface
public interface Specification<T> {
boolean isSatisfiedBy(T t);
Predicate toCollectionPredicate();
}
@Override
public Predicate toCollectionPredicate(Customer customer) {
Predicate<Customer> predicate =
new predicate<Customer>() {
@Override
public boolean apply(Customer input) {
return this.isSatisfiedBy(input);
}
};
return predicate;
}
Supported By:
BENTO
PRACTICE
CustomerIsPremium<Customer> spec= new CustomerIsPremium();
List<Customer> allCustomer = …
Collection<Customer> result =
Collections2.filter(
allCustomer,
spec.toCollectionPredicate()
);
assertArrayEquals(result, … testarray);
TEST PASSED
Supported By:
BENTO
PRACTICE
Specification Interface
public interface Specification<T> {
boolean isSatisfiedBy(T t);
Predicate toCollectionPredicate();
Predicate toPredicate(Root<T> root, CriteriaBuilder cb);
}
@Override
public Predicate toPredicate
(Root<Customer> root, CriteriaBuilder cb) {
return
cb.and (cb.greaterThan(root.get(Customer_.order),3)
);
}
Supported By:
BENTO
PRACTICE
public class DBRepository {
private EntityManager entityManager = ...
public <T> List<T> findAllBySpecification(Specification<T> specification) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
// use specification.getType() to create a Root<T> instance
CriteriaQuery<T> criteriaQuery = criteriaBuilder.createQuery(specification.getType());
Root<T> root = criteriaQuery.from(specification.getType());
// get predicate from specification
Predicate predicate = specification.toPredicate(root, criteriaBuilder);
// set predicate and execute query
criteriaQuery.where(predicate);
return entityManager.createQuery(criteriaQuery).getResultList();
}
}
Supported By:
BENTO
PRACTICE
CustomerIsPremium<Customer> spec= new CustomerIsPremium();
List<Customer> Customer = DBRepository.
findAllBySpecification(spec);
assertArrayEquals(result, … testarray);
TEST PASSED
Supported By:
SUMMARY
 Protect your invariants
 Use object as consistency boundaries
 Encapulate state and behavior with value object
 Encapulate Operations
 Use specification pattern
 Use predicate pattern
Supported By:
Questions ?
Supported By:
Identity CTM for Refactoring,
each monday
REFACTORING
Supported By:
Thanks

Refactoring domain driven design way

  • 1.
    REFACTORING CODE DOMAIN DRIVENDESIGN WAY Supported By:
  • 2.
    Supported By: I’M ANDIPANGERAN @andi_pangeran cybercoding.wordpress.com
  • 3.
    Supported By: AGENDA  PRACTICEHOW TO REFACTORING CODE BASED ON DOMAIN DRIVEN DESIGN MINDSET  PRACTICE HOW TO WRITE UNIT TESTING
  • 4.
    Supported By: JOKO Individual whohas significant expertise in the domain of the system being developed. DOMAIN EXPERT MEET OUR ACTOR
  • 5.
    Supported By: BENTO Individual whohas spend all of his life for coding. PROGRAMMER MEET OUR ACTOR
  • 6.
  • 7.
    Supported By: Protect yourinvariants REFACTORING
  • 8.
    Supported By: JOKO PRACTICE “A customermust always have an email address.”
  • 9.
    Supported By: PRACTICE BENTO public classCustomer { private String email; public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
  • 10.
    Supported By: PRACTICE BENTO public classCostumerTest { @Test public void should_always_have_an_email() { Customer customer = new Customer(); assertEquals(customer.getEmail(), "andi.pangeran@jtravl.com"); } } TEST FAIL
  • 11.
    Supported By: PRACTICE BENTO public classCostumerTest { @Test public void should_always_have_an_email() { Customer customer = new Customer(); customer.setEmail("andi.pangeran@jtravl.com"); assertEquals(customer.getEmail(), "andi.pangeran@jtravl.com"); } } TEST PASSED
  • 12.
    Supported By: PRACTICE BENTO public classCustomer { private String email; public Customer(String email) { this.email = email; } }
  • 13.
    Supported By: PRACTICE BENTO public classCostumerTest { @Test public void should_always_have_an_email() { Customer customer = new Customer("andi.pangeran@jtravl.com"); assertEquals(customer.getEmail(), "andi.pangeran@jtravl.com"); } } TEST PASSED
  • 14.
    Supported By: Use objectas concistency boundaries REFACTORING
  • 15.
    Supported By: JOKO PRACTICE “later prospectivecustomer can be upgraded to paying customer“ “Paying customer must have phone number” “we have two type of customer, prospective and paying customer.”
  • 16.
    Supported By: PRACTICE BENTO public classProspectiveCustomer extends Customer { /* other attribute */ } public class PayingCustomer extends Customer { /* other attribute */ private String phone; public PayingCustomer(String email, String phone) { super(email); this.phone = phone; } }
  • 17.
    Supported By: PRACTICE BENTO @Test public voidupgraded_prospective_paying() { ProspectiveCustomer pcustomer = new ProspectiveCustomer("andi.pangeran@jtravl.com"); assertEquals(pcustomer.getEmail(), "andi.pangeran@jtravl.com"); PayingCustomer payCustomer = new PayingCustomer(pcustomer.getName(), “0852xxx”); assertEquals(payCustomer.getEmail(), "andi.pangeran@jtravl.com"); assertEquals(payCustomer.getPhone(), " 0852xxx"); } TEST FAIL
  • 18.
    Supported By: PRACTICE BENTO @Test public voidupgraded_prospective_paying() { ProspectiveCustomer pcustomer = new ProspectiveCustomer("andi.pangeran@jtravl.com"); assertEquals(pcustomer.getEmail(), "andi.pangeran@jtravl.com"); PayingCustomer payCustomer = new PayingCustomer(pcustomer.getEmail(), “0852xxx”); assertEquals(payCustomer.getEmail(), "andi.pangeran@jtravl.com"); assertEquals(payCustomer.getPhone(), " 0852xxx"); } TEST PASSED
  • 19.
    Supported By: PRACTICE BENTO public classProspectiveCustomer extends Customer { /* other attribute */ public PayingCustomer upgradeToPayingCustomer(String phone) { return new PayingCustomer(this.email, phone); } } public class PayingCustomer extends Customer { /* other attribute */ private String phone; public PayingCustomer(String email, String phone) { super(email); this.phone = phone; } }
  • 20.
    Supported By: PRACTICE BENTO @Test public voidupgraded_prospective_paying() { ProspectiveCustomer pcustomer = new ProspectiveCustomer("andi.pangeran@jtravl.com"); assertEquals(pcustomer.getEmail(), "andi.pangeran@jtravl.com"); PayingCustomer payCustomer = pcostumer.upgradeToPaying(“0852xxx”); assertEquals(payCustomer.getEmail(), "andi.pangeran@jtravl.com"); assertEquals(payCustomer.getPhone(), " 0852xxx"); } TEST PASSED
  • 21.
    Supported By: JOKO PRACTICE “Paying customermust always have a valid phone number”
  • 22.
    Supported By: PRACTICE BENTO @Test public voidupgraded_prospective_paying() { PayingCustomer payCustomer = new PayingCustomer(“test@mail.com", “badphonenumber”); exception.expect(IllegalArgumentException.class); } TEST FAIL
  • 23.
    Supported By: PRACTICE BENTO public classPayingCustomer extends Customer { /* other attribute */ private String phone; public PayingCustomer(String email, String phone) { super(email); if (/* validation stuff of phone*/ ) { throw new IllegalArgumentException(); } this.phone = phone; } } TEST PASSED
  • 24.
    Supported By: PRACTICE BENTO public classPayingCustomer extends Customer { /* other attribute */ private String phone; public PayingCustomer(String email, String phone) { super(email); if (/* validation stuff of phone*/ ) { throw new IllegalArgumentException(); } this.phone = phone; } } TEST PASSED
  • 25.
    Supported By: Encapulate stateand behavior with value object REFACTORING
  • 26.
    Supported By: PRACTICE  Introto value object  Intro to immutable object
  • 27.
    Supported By: PRACTICE BENTO public classPhoneNumber { private final String phone; public PhoneNumber(String phone) { if (/* validation stuff of phone*/ ) { throw new IllegalArgumentException(); } this.phone = phone; } public String getPhone() { { return this.phone; } }
  • 28.
    Supported By: PRACTICE BENTO public classPayingCustomer extends Customer { /* other attribute */ private PhoneNumber phone; public PayingCustomer(String email, PhoneNumber phone) { super(email); this.phone = phone; } } TEST PASSED
  • 29.
    Supported By: PRACTICE BENTO @Test public voidupgraded_prospective_paying() { PayingCustomer payCustomer = new PayingCustomer(“test@mail.com", new PhoneNumber(“badphonenumber”)); exception.expect(IllegalArgumentException.class); } TEST PASSED
  • 30.
  • 31.
    Supported By: JOKO PRACTICE “a Customerorders product and pays for them”
  • 32.
    Supported By: Service.create BENTO Order order= new Order(); order.setCustomer(customer); order.setProducts(products); order.setStatus(PAYMENTSTATUS.UNPAID); order.setPaidAmount(500); order.setPaidCurrency(CURRENCY.IDR); order.setStatus(PAYMENTSTATUS.PAID); PRACTICE Service.pay
  • 33.
    Supported By: Service.create BENTO Order order= new Order(); order.setCustomer(customer); order.setProducts(products); order.setStatus(new PaymentStatus(PAYMENTSTATUS.UNPAID)); order.setPaidAmount(500); order.setPaidCurrency(CURRENCY.IDR); order.setStatus(new PaymentStatus(PAYMENTSTATUS.PAID)); PRACTICE Service.pay
  • 34.
    Supported By: Service.create BENTO Order order= new Order(); order.setCustomer(customer); order.setProducts(products); order.setStatus(new PaymentStatus(PAYMENTSTATUS.UNPAID)); order.setPaidMonetary(new Money(500, CURRENCY.IDR)); order.setStatus(new PaymentStatus(PAYMENTSTATUS.PAID)); PRACTICE Service.pay
  • 35.
    Supported By: Service.create BENTO Order order= new Order(customer, products); //set payment status in order constructor order.setPaidMonetary(new Money(500, CURRENCY.IDR)); order.setStatus(new PaymentStatus(PAYMENTSTATUS.PAID)); PRACTICE Service.pay
  • 36.
    Supported By: Service.create BENTO Order order= new Order(customer, products); //set payment status in order constructor order.pay (new Money(500, CURRENCY.IDR)); //set payment status in pay procedure PRACTICE Service.pay
  • 37.
  • 38.
  • 39.
  • 40.
    Supported By: JOKO PRACTICE “order 3times to become premium customer”
  • 41.
    Supported By: Specification Interface BENTO publicinterface Specification<T> { boolean isSatisfiedBy(T t); Class<T> getType(); } PRACTICE Specification Abstract abstract public class AbstractSpecification<T> implements Specification<T> { @Override public boolean isSatisfiedBy(T t) { throw new NotImplementedException(); } /othercode }
  • 42.
    Supported By: BENTO public classCustomerIsPremium extends AbstractSpecification<Customer> { private OrderRepository orderRepository public CustomerIsPremium(OrderRepository orderRepository) { this.orderRepository = orderRepository; } @Override public boolean isSatisfiedBy(Customer customer) { int count = this.orderRepository.countByCustomer(customer.getId); return (count > 3); } } PRACTICE
  • 43.
    Supported By: PRACTICE BENTO @Test public voidspecification_customer_premium() { CustomerIsPremium<Customer> spec= new CustomerIsPremium(); customer2order = … customer3order = … assertFalse(spec.isSatisfiedBy(customer2order)); assertTrue(spec.isSatisfiedBy(customer3order)); } TEST PASSED
  • 44.
    Supported By: JOKO PRACTICE “different rulesapply for different tenants.”
  • 45.
    Supported By: BENTO public classCustomerWith3OrdersIsPremium implement CustomerIsPremium {} public class CustomerWith500kPremium implement CustomerIsPremium {} public class CustomerWithSpecialRequiredmentPremium implement CustomerIsPremium {} PRACTICE Specification Interface public interface CustomerIsPremium extends Specification<Customer> { boolean isSatisfiedBy(Customer cust); }
  • 46.
    Supported By: BENTO PRACTICE public classSpecialOfferSender { private CustomerIsPremium premiumSpec public SpecialOfferSende(CustomerIsPremium premiumSpec) { this.orderRepository = orderRepository; } public void sendOffersTo(Customer customer) { if (this.premiumSpec.isSatisfiedBy(customer)) { //send offers } } }
  • 47.
    Supported By: Use Speficationfor Object Selection REFACTORING
  • 48.
    Supported By: JOKO PRACTICE “get alist of all premium customers”
  • 49.
    Supported By: PRACTICE  Introto predicate pattern  Collection predicate  JPA predicate
  • 50.
    Supported By: BENTO PRACTICE Specification Interface publicinterface Specification<T> { boolean isSatisfiedBy(T t); Predicate toCollectionPredicate(); } @Override public Predicate toCollectionPredicate(Customer customer) { Predicate<Customer> predicate = new predicate<Customer>() { @Override public boolean apply(Customer input) { return this.isSatisfiedBy(input); } }; return predicate; }
  • 51.
    Supported By: BENTO PRACTICE CustomerIsPremium<Customer> spec=new CustomerIsPremium(); List<Customer> allCustomer = … Collection<Customer> result = Collections2.filter( allCustomer, spec.toCollectionPredicate() ); assertArrayEquals(result, … testarray); TEST PASSED
  • 52.
    Supported By: BENTO PRACTICE Specification Interface publicinterface Specification<T> { boolean isSatisfiedBy(T t); Predicate toCollectionPredicate(); Predicate toPredicate(Root<T> root, CriteriaBuilder cb); } @Override public Predicate toPredicate (Root<Customer> root, CriteriaBuilder cb) { return cb.and (cb.greaterThan(root.get(Customer_.order),3) ); }
  • 53.
    Supported By: BENTO PRACTICE public classDBRepository { private EntityManager entityManager = ... public <T> List<T> findAllBySpecification(Specification<T> specification) { CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); // use specification.getType() to create a Root<T> instance CriteriaQuery<T> criteriaQuery = criteriaBuilder.createQuery(specification.getType()); Root<T> root = criteriaQuery.from(specification.getType()); // get predicate from specification Predicate predicate = specification.toPredicate(root, criteriaBuilder); // set predicate and execute query criteriaQuery.where(predicate); return entityManager.createQuery(criteriaQuery).getResultList(); } }
  • 54.
    Supported By: BENTO PRACTICE CustomerIsPremium<Customer> spec=new CustomerIsPremium(); List<Customer> Customer = DBRepository. findAllBySpecification(spec); assertArrayEquals(result, … testarray); TEST PASSED
  • 55.
    Supported By: SUMMARY  Protectyour invariants  Use object as consistency boundaries  Encapulate state and behavior with value object  Encapulate Operations  Use specification pattern  Use predicate pattern
  • 56.
  • 57.
    Supported By: Identity CTMfor Refactoring, each monday REFACTORING
  • 58.