Domain Modelling Patterns

Image
There are two main patterns for organizing business logic: the procedural Transaction script pattern, and the object-oriented Domain model pattern. 1. Transaction script pattern: An important characteristic of this approach is that the classes that implement behavior are separate from those that store state. When using the Transaction script pattern, the scripts are usually located in serviceclasses, which in this example is the OrderService class. A service class has one method for each request/system operation. The method implements the business logic for that request. It accesses the database using data access objects (DAOs), such as the OrderDao. The data objects, which in this example is the Order class, are pure data with little or no behavior. This style of design is highly procedural and relies on few of the capabilities of objectorientedprogramming (OOP) languages. This what you would create if you were writing the application in C or another non-OOP language. Neverthe...

Guice Tutorial

Below is a short & crisp tutorial on Guice and the functionalities offered by it

What is Guice?


Guice is framework in Java to inject dependencies to configure Java Objects. The dependency injection pattern leads to code that is more modular & testable.

Consider an interface BillingService as below:
public interface BillingService {
/**
* Attempts to charge the order to the credit card. Both successful and
* failed transactions will be recorded.
*
* @return a receipt of the transaction. If the charge was successful, the
* receipt will be successful. Otherwise, the receipt will contain a
* decline note describing why the charge failed.
*/
Receipt chargeOrder(PizzaOrder order, CreditCard creditCard);
}
view raw gistfile1.txt hosted with ❤ by GitHub
Consider below implementation of the BillingService Class:
public class RealBillingService implements BillingService {
public Receipt chargeOrder(PizzaOrder order, CreditCard creditCard) {
CreditCardProcessor processor = new PaypalCreditCardProcessor();
TransactionLog transactionLog = new DatabaseTransactionLog();
try {
ChargeResult result = processor.charge(creditCard, order.getAmount());
transactionLog.logChargeResult(result);
return result.wasSuccessful()
? Receipt.forSuccessfulCharge(order.getAmount())
: Receipt.forDeclinedCharge(result.getDeclineMessage());
} catch (UnreachableException e) {
transactionLog.logConnectException(e);
return Receipt.forSystemFailure(e.getMessage());
}
}
}
view raw gistfile1.txt hosted with ❤ by GitHub

It is easy to see the problems with above solutioning as it would make testing the code impossible!
Let's model the BillingService implementation by including its dependencies in constructor:
It is now possible to send mock Object or FakeCreditCard Object using a custom FakeCreditCardProcessor. But it still has a problem that BillingService's client need to lookup it dependencies , basically you will need to construct dependencies recursively while you need to use a service.

public class RealBillingService implements BillingService {
private final CreditCardProcessor processor;
private final TransactionLog transactionLog;
public RealBillingService(CreditCardProcessor processor,
TransactionLog transactionLog) {
this.processor = processor;
this.transactionLog = transactionLog;
}
public Receipt chargeOrder(PizzaOrder order, CreditCard creditCard) {
try {
ChargeResult result = processor.charge(creditCard, order.getAmount());
transactionLog.logChargeResult(result);
return result.wasSuccessful()
? Receipt.forSuccessfulCharge(order.getAmount())
: Receipt.forDeclinedCharge(result.getDeclineMessage());
} catch (UnreachableException e) {
transactionLog.logConnectException(e);
return Receipt.forSystemFailure(e.getMessage());
}
}
}
view raw gistfile1.txt hosted with ❤ by GitHub
This is where Guice comes for rescue!

Dependency Injection with Guice

To Use Guice for dependency injection in above example we need to do two things:
1. bind all the dependencies in a Java class that implements the Guice Module interface.
A module is a collection of bindings specified using fluent, English-like method calls
2. add @inject annotation on top of the class's constructor which will instruct Guice to use the bindings.
public class BillingModule extends AbstractModule {
@Override
protected void configure() {
bind(TransactionLog.class).to(DatabaseTransactionLog.class);
bind(CreditCardProcessor.class).to(PaypalCreditCardProcessor.class);
bind(BillingService.class).to(RealBillingService.class);
}
}
view raw gistfile1.txt hosted with ❤ by GitHub
We add @Inject to RealBillingService's constructor, which directs Guice to use it. Guice will inspect the annotated constructor, and lookup values for each parameter. The Injector can now be used to get an instance of any of the bound classes as below :
public static void main(String[] args) {
Injector injector = Guice.createInjector(new BillingModule());
BillingService billingService = injector.getInstance(BillingService.class);
...
}
view raw gistfile1.txt hosted with ❤ by GitHub

With dependency Injection , each object can accept dependency in their constructor ; it's dependency can also accept some dependencies in its own constructor.So when you build an object, you really need to build an object graph. Injector is basically the graph builder in Guice.

Type Of Bindings in Guice:
1. Linked Bindings
Linked Bindings map a type to its implementation as in the above example. It can link a class to its implementing class or an extending class.It can also be used to chain bindings i.e bind a concrete class to its subclass as below:
public class BillingModule extends AbstractModule {
@Override
protected void configure() {
bind(TransactionLog.class).to(DatabaseTransactionLog.class);
bind(DatabaseTransactionLog.class).to(MySqlDatabaseTransactionLog.class);
}
}
view raw gistfile1.txt hosted with ❤ by GitHub
In this case, when a TransactionLog is requested, the injector will return a MySqlDatabaseTransactionLog.
2. Binding Annotations
You can have use cases like you have more than 1 bindings for the same type.Let's say you have a PaypalCreditProcessor and GoogleCheckoutProcessor that you need to bind.In such case you can declare a BindingAnnotation as below:
@BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME)
public @interface PayPal {}
view raw gistfile1.txt hosted with ❤ by GitHub

Then, add this Bindingannotation "@paypal" while injecting inside the BillingService Constructor as below:
public class RealBillingService implements BillingService {
@Inject
public RealBillingService(@PayPal CreditCardProcessor processor,
TransactionLog transactionLog) {
...
}
view raw gistfile1.txt hosted with ❤ by GitHub

You then need to bind as below using "annotatedwith":
bind(CreditCardProcessor.class)
.annotatedWith(PayPal.class)
.to(PayPalCreditCardProcessor.class);
view raw gistfile1.txt hosted with ❤ by GitHub

So you need to do 3 things in essence : 1.Declare a BindingAnnotation with an apt name for the annotation , 2.While Injecting in the constructor add the annotation with the Object, 3.use "annotatedWith" while defining bindings in the module.
Guice also comes with a built-in binding annotation @Named , here you won't need to create a binding annotation.
public class RealBillingService implements BillingService {
@Inject
public RealBillingService(@Named("Checkout") CreditCardProcessor processor,
TransactionLog transactionLog) {
...
}
view raw gistfile1.txt hosted with ❤ by GitHub

You need to use Names.named with the "annotatedWith" as below:
bind(CreditCardProcessor.class)
.annotatedWith(Names.named("Checkout"))
.to(CheckoutCreditCardProcessor.class);
view raw gistfile1.txt hosted with ❤ by GitHub

3. Instance Bindings
You can also bind an type to a particular instance of that type
bind(String.class)
.annotatedWith(Names.named("JDBC URL"))
.toInstance("jdbc:mysql://localhost/pizza");
bind(Integer.class)
.annotatedWith(Names.named("login timeout seconds"))
.toInstance(10);
view raw gistfile1.txt hosted with ❤ by GitHub

Avoid doing it with complex Objects as it will slow down application startup use @Provides instead.
4. @Provides Method
This method is used when you want to bind an instance to a type just like instance binding. The method must be defined within a module, and it must have an @Provides annotation. The method's return type is the bound type. Whenever the injector needs an instance of that type, it will invoke the method.
public class BillingModule extends AbstractModule {
@Override
protected void configure() {
...
}
@Provides
TransactionLog provideTransactionLog() {
DatabaseTransactionLog transactionLog = new DatabaseTransactionLog();
transactionLog.setJdbcUrl("jdbc:mysql://localhost/pizza");
transactionLog.setThreadPoolSize(30);
return transactionLog;
}
}
view raw gistfile1.txt hosted with ❤ by GitHub

In case of Named annotations like @Named("paypal") you can mention Names.named("paypal") with the Object as done previously in the constructor.
@Provides @Named("paypal")
CreditCardProcessor providePayPalCreditCardProcessor(
@Named("PayPal API key") String apiKey) {
PayPalCreditCardProcessor processor = new PayPalCreditCardProcessor();
processor.setApiKey(apiKey);
return processor;
}
view raw gistfile1.txt hosted with ❤ by GitHub

Use this as below:
public class RealBillingService implements BillingService {
@Inject
public RealBillingService(@Named("Checkout") CreditCardProcessor processor,
TransactionLog transactionLog) {
...
}
view raw gistfile1.txt hosted with ❤ by GitHub

5. JIT Bindings
@ImplementedBy:
It acts as a basic linked binding , but it has lower precedence than the "bind" method declared inside the Guice module.
@ImplementedBy(PayPalCreditCardProcessor.class)
public interface CreditCardProcessor {
ChargeResult charge(String amount, CreditCard creditCard)
throws UnreachableException;
}
view raw gistfile1.txt hosted with ❤ by GitHub

@ProvidedBy:
@ProvidedBy tells the injector about a Provider class that produces instances
@ProvidedBy(SpellCheckerProvider.class)
interface SpellChecker {
public void checkSpelling();
}
view raw gistfile1.txt hosted with ❤ by GitHub

class SpellCheckerProvider implements Provider<SpellChecker> {
@Override
public SpellChecker get() {
String dbUrl = "jdbc:mysql://localhost:5326/emp";
String user = "user";
int timeout = 100;
SpellChecker SpellChecker = new SpellCheckerImpl(dbUrl, user, timeout);
return SpellChecker;
}
}
view raw gistfile1.txt hosted with ❤ by GitHub

Comments

Popular posts from this blog

Domain Modelling Patterns

Introduction to Kafka