DESIGN PATTERNS - JAVA: Learn JAVA Quickly (2017)

JAVA: Learn JAVA Quickly (2017)

CHAPTER 10. DESIGN PATTERNS

SINGLETON PATTERN

Singleton pattern is one of most commonly used design patterns. He belongs tocreational pattern category. Pattern restrict object creations and ensures that only one instance of class exists. Imagine that you only need one garage at home, only one HR at company, only one captain at team. That are examples from real life in whose you will need singleton pattern. For implementation of pattern we need some conditions:

· private constructor - We didn`t explained in constructor section, but in short private constructor doesn`t give class to be instantiated from another class

· private static instance – only instance of the class

· public static method – method which returns instance of class

There are two types of making class singleton:

· Lazy initialization

To better figure out what exactly means this three conditions, let`s see out code below:

private SingletonOne(){

}

privatestatic SingletonOne instance;

publicstatic SingletonOne getInstance(){

if(instance == null){

instance = new SingletonOne();

}

returninstance;

}

Creation of Class object is derived to getInstance() method. As public static method have global access and there is no need for object for calling, static method is called by class name. This type of singleton pattern is called lazy because instance of Class is not created until getInstance() method is called. getInstance() method checks if there is already instance, is it is false (null) method creates new one (new CLass())and return it.With lazy initialization you crate instance only when its needed and not when the class is loaded. So you escape the unnecessary object creation.

· Eager initialization

privatestaticfinal SingletonTwo instance = new SingletonTwo();

private SingletonTwo(){}

publicstatic SingletonTwo getInstance(){

returninstance;

}

Unlike lazy initialization, eager initialization is done when class is loaded. So, difference is that in first approach you get instance of singleton class only when you actually need it.

MVC PATTERN

MVC pattern is maybe most common used pattern in making Java applications. As name tells, this is acronym of Model – View – Controller

· Model – represents data or POJO classes. POJO is just declaration which must match some conditions like: public default no-arg constructor, private attributes and getters and setters.

· View – represents view of mentioned attributes.

· Controller – controller behaves between both model and view, it updates view based on changes from model.

For our explanation we need classes below:

publicclass Doctor {

private String name;

privateintage;

Doctor() {}

public String getName() {

returnname;

}

publicvoid setName(String name) {

this.name = name;

}

publicint getAge() {

returnage;

}

publicvoid setAge(intage) {

this.age = age;

}

}

Class Doctor represents our model. If you remember, default no-arg constructor will be made by default by compiler, but we did it just to don`t make confusion.

publicclass ShowDoctor {

publicvoid showDoctor(String name, intage) {

System.out.println("Doctor with name: " + name + " and age: " + age);

}

}

This class represent String presentation, view, of our Doctor with attributes name and age.

publicclass Controller {

private Doctor doctor;

private ShowDoctor showD;

Controller(Doctor d, ShowDoctor s) {

this.doctor = d;

this.showD = s;

}

public Doctor getDoctor() {

returndoctor;

}

publicvoid setDoctor(Doctor doctor) {

this.doctor = doctor;

}

public ShowDoctor getShowD() {

returnshowD;

}

publicvoid setShowD(ShowDoctor showD) {

this.showD = showD;

}

void shomMeDoctor() {

showD.showDoctor(doctor.getName(), doctor.getAge());

}

}

As you can see, our controller takes references from both model and view classes. Now we need one class to manage with all this classes.

publicclass Program {

Doctor doctor = setDoctorAttributes();

ShowDoctor show = newShowDoctor();

Controller controller = newController(doctor, show);

privatestatic Doctor setDoctorAttributes(){

Doctor doc = newDoctor();

doc.setName("Bob");

doc.setAge(50);

returndoc;

}

void printDoctor(){

controller.shomMeDoctor();

}

publicstaticvoid main(String[] args){

Program program = newProgram();

program.printDoctor();

}

}

Program is class with main method, you remember that main method is used for calling other methods. Our whole program would not be possible to start without it, so we needed to create object of current class. We provided references of Doctor, ShowDoctor and Controller to current class. Association is here used for code reusing. Because we don`t have doctor, method setDoctorAttributes() is made to set values. It is done by using doc reference and setName() and setAge() method, in other words setters. This method is derived to doctor reference. We don’t create new doctor by newDoctor();Output is: Doctor with name: Bob and age: 50

PROJECT

Everything that we covered until now have his own usage and it is very important part of Java programing. But they are only parts of one big “story”. Best way for learning something, Java also, is to use it on real problems, in this case in project. In this last section, we will try to make from all (almost all) that we learned, one functional project. Based on this you will have clearerpicture how and when to use some features of Java. Idea is to make a project Hospital.

Characteristics of Hospital are:

· Doctor (name, surname, specialty) have many Patient (name, surname, medical record number)

· Patient can have only one Doctor

· Doctor assigns laboratory examination to Patient

· Examination have date and time

· Types of examinations:

Ø Blood sugar level (upper value, lower value, pulse)

Ø Blood pressure (value, last time meal)

Make script that simulates next:

1. Create Doctor “Bob Williams”

2. Create Patient “Fill Kane”

3. Patient “Fill” chooses “Bob” to be his Doctor

4. Doctor “Bob” calls Patient “Fill” for blood sugar level examination

5. Doctor “Bob” calls Patient “Fill” for blood pressure examination

6. Examinations have examinationID and date values

7. Show results for both examinations

Start to think about project with entities, Doctor and Patient, are they have something similar? Do we maybe need abstract class? Is this also case with examinations? How to derive only one doctor to patient? Singleton pattern?

Let`s start making our project to better figure out all of this.

In Eclipse create a new project Hospital. Our entities will be placed inside model package. Every hospital has entities like Doctor and Patient, our also will. First, we will make abstract class Person:

protected String nin;

protected String name;

protected String surname;

public Person(String n, String name, String surname){

this.nin = n;

this.name = name;

this.surname = surname;

}

Generate getters and setters for nin, name and age attributes also.nin stands for National Identity Number.Next class is Doctor:

publicclass Doctor extends Person{

private String specialty;

public Doctor(String n, String name, String surname, String spec){

super(n, name, surname);

this.specialty = spec;

}

}

Also, generate getters and setters for specialty attribute. Patient class:

publicclass Patient extends Person{

privateintmedicalRecordNumber;

public Patient(String n,String name, String surname, intmedRecNum){

super(n, name, surname);

this.medicalRecordNumber = medRecNum;

}

}

Getters and setters for medicalRecordNumber.

Our next job to do is to assign doctor to patient. We have condition, our patient can have only one doctor. You can guess, singleton pattern need to be implemented. Use lazy initialization in Hospital class:

private Hospital(){

}

privatestatic Hospital instance;

publicstatic Hospital getInstance(){

if(instance == null){

instance = new Hospital();

}

returninstance;

}

Doctor and patients need to be stored somewhere. We will use HashMap for that. Add this to Hospital class:

private Map<String, Person>persons = new HashMap<String, Person>();

Our Hospital also needs methods for manipulationg with persons.

private Person TryGetPerson(String nin){

returnpersons.get(nin);

}

public Doctor TryGetDoctor(String nin){

Doctor doct;

doct = (Doctor)TryGetPerson(nin);

returndoct;

}

public Patient TryGetPatient(String nin){

Patient patient;

patient = (Patient)TryGetPerson(nin);

returnpatient;

}

Method TryGetPerson() returns person with his nin. To decide if that person is doctor or patient, we need TryGetDoctor() and TryGetPatient() methods.

Note: Look at script. At 7. it says we need to show results. For this purpose, we will use log4j, new for us but very simple feature. Download jar file from this site: http://www.java2s.com/Code/Jar/l/Downloadlog4jjar.htm

Extract file and add jar file to project by Right click ->Properties ->Java Build Path ->Add External JARs ->log4j

Below class name Hospital, add our Logger:

static Logger log = Logger.getLogger(Hospital.class);

Now is order to make methods which actually create doctor and patient:

publicvoid createDoctor(String nin, String name, String surname, String spec){

if(TryGetDoctor(nin) == null&& !persons.containsKey(nin)){

Doctor doctor = newDoctor(nin, name, surname, spec);

persons.put(nin, doctor);

log.info("Doctor " + name + " " + surname + " with speciality " + spec + "is created!");

}else{

log.info("Doctor " + name + " " + surname + " already exists!");

}

}

publicvoid createPatient(String nin, String name, String surname, intmedRecNum){

if(TryGetPatient(nin) == null&& !persons.containsKey(nin)){

Patient patient = newPatient(nin, name, surname, medRecNum);

persons.put(nin, patient);

log.info("Patient " + name + " " + surname + " with medical record " + medRecNum + " is created!");

}else{

log.info("Patient " + name + " " + surname + " already exists!");

}

}

Both methods are doing same thing. HashMap takes input by key/value. In this case nin is key, so in our methods we are checking if person doesn`t exists. If it is true, then we are creating a new one. If it is false we are printing some massage. containsKey() method isn`t covered, it checks if map contains a mapping for the specified key.

Next step is to assign patient to doctor. First we need some method in Patient class for assigning to doctor. Method is similar like this two above:

private Doctor assign;

publicvoid assignDoctor(Doctor doc){

if(Hospital.getInstance().TryGetDoctor(doc.JMBG) != null){

assign = doc;

log.info("Patient is assigned to " + doc.getName() + " "+ doc.getSurname());

}else{

log.info("Doctor " + doc.getName() + " " + doc.getSurname() + " doesn`t exists!");

}

}

Our method is using reference of Doctor class to assign type of Doctor to itself.

Note: Also add logger to Patient class.

static Logger log = Logger.getLogger(Hospital.class);

In beginning it sad that doctor can have many patients, so we also need HashMap for that patients, inside Doctor class of course:

private Map<String, Patient>patients = new HashMap<String, Patient>();

This map again need method for putting patients inside. Let`s create her:

publicvoid addPatient(Patient patient){

if(Hospital.getInstance().TryGetPatient(patient.nin) != null){

patients.put(nin, patient);

}

}

Class Hospital now need method to implement assignDoctor() method:

publicvoidassignDoctorToPatient(Doctor doctor, Patient patient){

patient.assignDoctor(doctor);

}

Now is time to move on examinations. It is sad that each examination have ID and date as common attributes, so in this case we also can use concept of abstract classes. LaboratoryExaminationwill be our abstract class:

publicabstractclass LaboratoryExamination {

publicintexaminationID;

public Date date;

public LaboratoryExamination(intexam, Date date){

this.examinationID = exam;

this.date = date;

}

}

Don`t forget to generate getters and setters, also import java.util.Date class. We are not discussed about this, but compiler will complain to import classes like Map, HashMap and Hospital to Doctor and Patient classes. Just do it.

BloodSugarLevel class:

publicclass BloodSugarLevel extends LaboratoryExamination{

privatedoublevalue;

private Date lastMealTime;

public BloodSugarLevel(intexam, Date date, doublevalue, Date last){

super(exam, date);

this.value = value;

this.lastMealTime = last;

}

public BloodSugarLevel(intexam, Date date){

super(exam, date);

}

}

BloodPressure class:

publicclass BloodPressure extends LaboratoryExamination{

privateintupperValue;

privateintlowervalue;

privateintpulse;

public BloodPressure(intexam, Date date, intupper, intlower, intpulse){

super(exam, date);

this.upperValue = upper;

this.lowervalue = lower;

this.pulse = pulse;

}

public BloodPressure(intexam, Date date){

super(exam, date);

}

}

Again, getters and setters!

Before we make last one methods for examination manipulations, we need class that will hold references from Patient, Doctor and LaboratoryExamination classes. You will see latter why, so create PatientDoctorExamination class:

private Doctor doctor;

private Patient patient;

private LaboratoryExamination labExam;

publicPatientDoctorExamination(Doctor doc, Patient pat, LaboratoryExamination ladExamination){

this.doctor = doc;

this.patient = pat;

this.labExam = ladExamination;

}

As always, getters and setters need to be generated in this class.

Let`s finish with our Hospital class. Like with persons, we need HashMap for examinations:

private Map<Integer, PatientDoctorExamination>examinations = new HashMap<Integer, PatientDoctorExamination>();

Here you can see usage of previous PatientDoctorExamination class. Also, we need something that will store our examinations. For this, let`s use enum in Hospital class:

publicenum laboratoryExaminations{

bloodPressure,

bloodSugarLevel,

}

Ok, but as always, we need something to do with our data, examinations. Method need to put our examination to HashMap based on input. One more thing that we covered earlier will be used, switch, so add method to Hospital class:

privateintexamID;

publicint ScheduleExamination(Doctor doctor, Patient patient, Date date, laboratoryExaminations examinationsLab){

LaboratoryExamination examination = null;

switch(examinationsLab){

casebloodPressure:

examination = new BloodPressure(examID, date);

break;

casebloodSugarLevel:

examination = new BloodSugarLevel(examID, date);

break;

}

examinations.put(examID, new PatientDoctorExamination(doctor, patient, examination));

examID++;

returnexamination.examinationID;

}

Last one thing that we need to do in Hospital class to make it functional is to somehow make methods that are finally making examinations. This will be shown is code below:

publicvoid FillBloodSugarLevelExamination(intexaminationID, doublevalue, Date date){

PatientDoctorExamination patientDoctorExamination = null;

patientDoctorExamination = examinations.get(examinationID);

if(patientDoctorExamination != null){

if(patientDoctorExamination.getLabExam() instanceof BloodSugarLevel){

BloodSugarLevel bloodSugarLevel = (BloodSugarLevel)patientDoctorExamination.getLabExam();

bloodSugarLevel.setValue(value);

bloodSugarLevel.setLastMealTime(date);

log.info("Examination is successfully done! \n" +"=======\n"+ "value: " + value + ", last meal time: " + date);

}else

log.info("Selected examination is not for blood sugar level!");

}else

log.info("Selected examination does not exist!");

}

publicvoid FillBloodPressureExamination(intexaminationID, intupperValue, intlowerValue, intpulse){

PatientDoctorExamination patientDoctorExamination = null;

patientDoctorExamination = examinations.get(examinationID);

if(patientDoctorExamination != null){

if(patientDoctorExamination.getLabExam() instanceof BloodPressure){

BloodPressure bloodPressure = (BloodPressure)patientDoctorExamination.getLabExam();

bloodPressure.setUpperValue(upperValue);

bloodPressure.setLowervalue(lowerValue);

bloodPressure.setPulse(pulse);

log.info("Examination is successfully done! \n" +"=======\n"+"upper value: " + upperValue + ", lower value: " + lowerValue + ", pulse: " + pulse);

}else

log.info("Selected examination is not for blood pressure!");

}else

log.info("Selected examination does not exist!");

}

Now when all characteristics and conditions are satisfied, only thing that is left to do is to create class with main method to see output of our program. Hope you didn`t forgot that all classes, except Hospital, were supposed to be in model package. Hospital and ProgramHospitalclass, which will be made now, are placed in program package. While creation of this class, add main method, and following lines inside:

org.apache.log4j.BasicConfigurator.configure();

Hospital.getInstance().createDoctor("1234", "Bob", "Williams", "surgeon");

Hospital.getInstance().createPatient("2345", "Fill", "Kane", 25);

Doctor doctor = Hospital.getInstance().TryGetDoctor("1234");

Patient patient = Hospital.getInstance().TryGetPatient("2345");

Note: Don`t get confused about first line of code, it`s just configuring our log4j.

As you can see, when class is singleton, methods that are inside her are only available to be called through getInstance() static method. First, we created doctor and patient, so they are in HashMap now. Next step is where we stored our doctor and patient to doctor and patient references. Finally, we assigned them to each other. And last part is to delegate examinations to patient:

intexamination1 = Hospital.getInstance().ScheduleExamination(doctor, patient, new Date(), laboratoryExaminations.bloodSugarLevel);

intexamination2 = Hospital.getInstance().ScheduleExamination(doctor, patient, new Date(), laboratoryExaminations.bloodPressure);

Hospital.getInstance().FillBloodSugarLevelExamination(examination1, 12 new Date());

Hospital.getInstance().FillBloodPressureExamination(examination2, 120, 90, 32);

Previously you can clearly recognize what this methods do. They fill schedule examinations.

Run program.