You are on page 1of 1

Sign in Get started

S OFT WARE P ROJECT MANAGEMENT MARKET ING S INGULAR LOOP GROW WIT H US

Java — good practices and


recommendations: Design patterns
Martin Jonovski Follow
Feb 22, 2019 · 10 min read

Originally published on culture.singular.uk

Design patterns are common solutions to problems that occur frequently


during software development. These solutions offer elegant and in most
cases, the most effective way of solving different problems related with
object creation, resource allocation, simplifying code etc. The context in
which they are given needs to be maintained, while the solution itself
needs to be customised, according to the business logic.

Design patterns are separated in three categories:

creational, offer solutions for solving different problems that occur


during object creation

structural, offer solution to instantiation problems by finding ways


how the classes can be composed in larger structures

behavioral, offer solutions to problems that happen in the


communication between separate parts of the code.

Some of the design patterns can actually be used as guidelines during the
design of the architecture like it’s the case with the DAO design pattern.
Software architectures usually have three layers: the endpoints for the Top highlight

app, the service layer i.e. the business logic and the data layer.

The data layer is implemented by using DAO design pattern (Data


Access Object) which separates the part that communicates with the
database from the rest of the application. The DAO pattern defines the
CRUD (create,read,update,delete) operations for all of the entities. By
adding named/native queries, that will be used frequently for the entity
itself, the persistence layer can be completely separated.

public interface DAO<T,E extends Serializable>{


public T save(T object);
public Boolean delete(T object);
public T update(T object);
public T find(E id);
}

The interface for the DAO itself defines only the operations that need to
be specified in the implementation. The implementation itself uses
generic types with provided entity manager. The entity manager is a class
that takes care of all the persistence operations in the app and can be
obtained using the application context.

public abstract class GenericDAO<T,E> implements DAO<T,E>{

@PersistenceContext
private EntityManager entityManager;

public T save(T object){


return entityManager.persist(object);
}

public T find(E id){


return entityManager.find(T.class,id);
}

public Boolean delete(T object){


return entityManager.remove(object);
}

public T update(T object){


return entityManager.merge(object);
}
}

The example provided requires basic understanding of Hibernate and


persistence with Java. Hibernate is an ORM tool (object relational
mapping) which creates tables from java code and uses HQL (hibernate
query language) for query typing and execution.

@Entity
@Table(name="person")
@NamedQueries
(
{
@NamedQuery(name=Person.GET_PERSON_BY_AGE,query="Select * from
User u where u.age>:age")
}
)
public class Person{

public static final String GET_PERSON_BY_AGE =


"Person.getPersonByAge";

@Id
@GeneratedValue( strategy = GenerationType.IDENTITY)
@Column(name="id",unique="true")
public int id;

@Column(name="name")
public String name;

public Person(String name){


this.name=name;
}

//getters and setters...

The DAO class which will be used for the entity extends the generic DAO
in which are implemented the basic CRUD operations, so we only need to
add the specific queries that will be used.

public PersonDAO extends GenericDAO<Person,Integer>{

public List<Person> getPersonByAge(int age){


Query q=entityManager.createNamedQuery(Person.GET_PERSON_BY_AGE,
Person.class);
q.setParameter("age",5);
return (List<Person>)q.getResultList();
}
}

Pros:

offers both logical and physical separation of the code from the
business logic, which is easy to implement;

the DAO classes can be expanded easily with cache strategies, that can
be implemented in the methodsi;

If the DAO class is declared as an EJB, each method can specify the
transactional attribute in order to control the scope of the underlying
transaction;

Cons:

it creates an overhead in the connection with the database, because


DAO objects generally handle the whole object. This is an advantage
when it comes to the save operation because the whole object is
stored at once but the read can be an expensive operation;

to avoid this, native or named queries can be used in order to retrieve


smaller portions of the object, according to the business needs;

DAO pattern should not be used in small apps, because its advantages
would be minor and the code will become more complex;

Design patterns are often used to simplify big chunks of code or even to
hide specific implementations from the application flow. The perfect
example for these kind of problems is the factory design pattern, which is
a creational design pattern that offers object creation without having to
specify the exact class of the objects. It proposes using a super class and
multiple sub-classes, which inherit from the super class. During
execution only the super class is used and its value varies depending on
the factory class.

public class Car{

private String model;


private int numberOfDoors;

public Car(){
}

public String getModel(){


return this.model;
}

public int getNumberOfDoors(){


return this.numberOfDoors;
}

public void setModel(String model){ this.model = model; }


public void setNumberOfDoors(int n){ this.numberOfDoors = n; }

public class Jeep extends Car{

private boolean land;

public Jeep(){
}

public void setLand(boolean land){


this.land=land;
}

public boolean getLand(){


return this.land;
}
}

public class Truck extends Car{

private float capacity;

public Truck(){
}

public void setCapacity(float capacity){


this.capacity=capacity;
}

public float getCapacity(){


return this.capacity;
}

In order to use this pattern, we need to implement a factory class, which


will return the correct sub-class for a given input. The java classes above
specify one super class (Car.java) and two sub-classes (Truck.java and
Jeep.java). In our implementation we instantiate an object of the Car
class and depending on the arguments, the factory class will decide
whether it’s a Jeep or a Truck.

public class CarFactory{

public Car getCarType(int numberOfDoors, String model,Float


capacity, Boolean land){
Car car=null;
if(capacity!=null){
car=new Jeep();
//implement setters
}else{
car=new Truck();
//implement setters
}
return car;
}

During runtime, the factory class instantiates the correct sub-class,


considering the input.

public static void main(String[] args){


Car c=null;
CarFactory carFactory=new CarFactory();
c = carFactory.getCarType(2,"BMW",null, true);
}

Abstract factory design pattern works in the same way but instead of a
regular class, the parent class is an abstract class. Abstract classes are
generally faster and easier to instantiate, because they are basically
empty. The implementation is the same only the parent class is declared
as abstract with all its methods and the sub-classes need to implement
the behaviour of the methods declared in the abstract class.

The example for the Abstract factory is created using interfaces. The
same can be done by simply replacing the interface with an abstract class
and instead of implementing the interface, the sub-classes will extend
the abstract class.

public interface Car {

public String getModel();


public Integer getNumberOfDoors();
public String getType();

public class Jeep implements Car{


private String model;
private Integer numberOfDoors;
private Boolean isLand;

public Jeep() {}

public Jeep(String model, Integer numberOfDoors, Boolean isLand){


this.model = model;
this.numberOfDoors = numberOfDoors;
this.isLand = isLand;
}

public String getModel(){


return model;
}

public Integer getNumberOfDoors() {


return numberOfDoors;
}

public Boolean isLand() {


return isLand;
}

public void setLand(Boolean isLand) { this.isLand = isLand; }

public void setModel(String model) { this.model = model; }

public void setNumberOfDoors(Integer numberOfDoors){


this.numberOfDoors = numberOfDoors;
}

public String getType(){


return "jeep";
}

public class Truck implements Car{

private String model;


private Integer numberOfDoors;
private Integer numberOfWheels;

public Truck(String model, Integer numberOfDoors, Integer


numberOfWheels) {
this.model = model;
this.numberOfDoors = numberOfDoors;
this.numberOfWheels = numberOfWheels;
}

public Truck() {}

public String getModel() { return model; }

public Integer getNumberOfDoors() { return numberOfDoors; }

public Integer getNumberOfWheels() { return numberOfWheels; }

public void setNumberOfWheels(Integer numberOfWheels) {


this.numberOfWheels = numberOfWheels;
}

public void setModel(String model) { this.model = model; }

public void setNumberOfDoors(Integer numberOfDoors) {


this.numberOfDoors = numberOfDoors;
}

public String getType(){ return "truck"; }

public class CarFactory {

public CarFactory(){}

public Car getCarType(String model,Integer numberOfDoors, Integer


numberOfWheels, Boolean isLand){
if(numberOfWheels==null){
return new Jeep(model,numberOfDoors,isLand);
}else{
return new Truck(model,numberOfDoors,numberOfWheels);
}
}

The only difference is that the methods declared in the abstract class
must be implemented in each of the sub-classes. The factory and the
main method stay the same in both cases.

public class CarMain {

public static void main(String[] args) {


Car car=null;
CarFactory carFactory=new CarFactory();

car=carFactory.getCarType("Ford", new Integer(4), null, new


Boolean(true));

System.out.println(car.getType());
}
}

The output is the following:

Pros:

it allows loose coupling and a higher level of abstraction;

it is scalable and can be used to separate certain implementations


away from the application;

the factory class can be reused after creating new classes lower in the
hierarchy and the code will still work, by simply adding the
appropriate instantiation logic;

unit testing, because it is simple to cover all of the scenarios by using


the super class;

Cons:

it is often too abstract and hard to understand;

it is really important to know when to implement the factory design


pattern, because in small applications it just creates an overhead
(more code) during object creation;

the factory design pattern must maintain its context i.e. only classes
that inherit from the same parent class or implement the same
interface can be applicable for the factory design pattern.

The singleton design pattern is one of the most famous and


controversial creational design patterns. A singleton class is a class
which will be instantiated only once during the lifetime of the application
i.e. there will be only one object shared for all the resources. The
singleton methods are thread safe and may be used by multiple parts of
the application at the same time, even when they access a shared
resource within the Singleton class. The perfect example on when to use
a singleton class is a logger implementation, in which all the resource
write in the same log file and is thread safe. Other examples include
database connections and shared network resources.

Also, whenever the application needs to read a file from the server it is
convenient to use a Singleton class, because in that case only one object
of the application will be able to access the files stored on the server.
Besides the logger implementation, the config files are another example
where the use of a singleton class is efficient.

In java, a singleton is a class with a private constructor. The singleton


class keeps a field with the instance of the class itself. The object is
created using the get method, which calls the constructor if the instance
hasn’t been initiated yet. Earlier, we mentioned that this pattern is the
most controversial and it is so because of the multiple implementations
for the instance generation. It must be thread safe, but it also must be
efficient. In the examples we have two solutions.

import java.nio.file.Files;
import java.nio.file.Paths;

public class LoggerSingleton{

private static Logger logger;


private String logFileLocation="log.txt";
private PrintWriter pw;
private FileWriter fw;
private BufferedWriter bw;

private Logger(){
fw = new FileWriter(logFileLocation, true);
bw = new BufferedWriter(fw)
this.pw = new PrintWriter(bw);
}

public static synchronised Logger getLogger(){


if(this.logger==null){
logger=new Logger();
}
return this.logger;
}

public void write(String txt){


pw.println(txt);
}
}

Because the log file will be accessed frequently. the print writer using a
buffered writer makes sure that the file won’t be opened and closed
multiple times.

The second implementation includes a private class which holds a static


field of the instance of the Singleton class. The private class can only be
accessed within the singleton class i.e. only from the get method.

public class Logger{

private static class LoggerHolder(){


public static Singleton instance=new Singleton();
}

private Logger(){
// init
}

public static Logger getInstance(){


return LoggerHolder.instance;
}
}

The singleton class then can be used from any other class inside the app:

Logger log=Logger.getInstance();
log.write("something");

Pros:

the singleton class is instantiated only once in the life cycle of the app
and it can be used as many times needed;

the singleton class allows thread safe access to shared resources;

the singleton class cannot be extended and if it is implemented


correctly i.e. the get method should be synchronised and static, it is
thread safe;

it is recommended to create an interface first and then design the


singleton class itself, because it is easier to test the interface;

Cons:

problems during testing, when the singleton class accesses a shared


resource and the execution of the tests is important;

the singleton class also hides some of the dependencies in the code
i.e. creates dependencies that are not explicitly created;

the problem with using singleton without a factory pattern, is that it


breaks the single responsibility principle, because the class is
managing its own life cycle;

The builder pattern is also a creational pattern which allows


incremental creation for complex objects. It is recommended to use this
pattern when the field setting demands complex operations or simply the
field list is simply too long. All of the fields for the class are kept in a
private inner class

public class Example{

private String txt;


private int num;

public static class ExampleBuilder{

private String txt;


private int num;

public ExampleBuilder(int num){


this.num=num;
}

public ExampleBuilder withTxt(String txt){


this.txt=txt;
return this;
}

public Example build(){


return new Example(num,txt);
}
}

private Example(int num,String txt){


this.num=num;
this.txt=txt;
}

In real cases, the list of arguments will be longer and some of the
arguments for the class can be calculated based on other input. The
builder class has the same fields as the class itself and it must be declared
static in order to be accessed without having to instantiate an object of
the holder class (in this case Example.java). The implementation given
above is thread safe and can be used in the following way:

Example example=new ExampleBuilder(10).withTxt("yes").build();

Pros:

the code is more neat and reusable if the number of arguments in the
class is bigger than 6 or 7;

the object is created after setting all the needed fields and only fully
created objects are available;

the builder pattern hides some of the complex calculations inside the
builder class and separates it from the application flow;

Cons:

the builder class must contain all the fields from the original class, so
that can take a little more time to develop compared to using the class
alone;

Observer design pattern is a behavioural design pattern which observes


certain entities and handles the changes by propagating them to the
concerned parts of the application. Each container can offer a different
implementation for different design patterns and the observer pattern
has an implementation in java using the interface Observer for the class
which will be affected by the changes in the observer class. On the other
side, the observed class needs to implement the Observable interface.
The Observer interface has only the update method but it has been
deprecated in Java 9, because it is not recommended for usage due to its
simplicity. It doesn’t offer details about what has changed and simply
finding the changes in bigger objects can be a costly operation. The
recommended alternative is the PropertyChangeListener interface which
can specify the actions following the update.

T hanks to Elena Mihajloska.

Java Design Patterns Singleton Dao Factory

674 claps

WRIT T EN BY

Martin Jonovski Follow

< BE OUTSTANDING /> Follow

Your go-to publication about growth, challenges and


opportunities.

Write the rst response

More From Medium

A short summary of Java Practical Guide to Java Framework-less REST Hibernate : Mistakes to
coding best practices Stream API API in Java avoid
Ra ullah Hamedy Praveer Gupta in Praveer’s marcin piczkowski in Marcin Manika Singh
Musings Piczkowski

Design Patterns —Zero A Study List for Java 4 T hings T hat are most How to Write Better
to Hero —Singleton Developers confusing for Java Code with Java 8’s
Pattern Jim Developer Optional
Parathan T hiyagalingam Himanshu Verma in T he Code Somnath Musib in T he Startup
Monster

Discover Medium Make Medium yours Become a member


Welcome to a place where words matter. On Medium, smart Follow all the topics you care about, and we’ll deliver the Get unlimited access to the best stories on Medium — and
voices and original ideas take center stage - with no ads in best stories for you to your homepage and inbox. Explore support writers while you’re at it. Just $5/month. Upgrade
sight. Watch

About Help Legal

You might also like