In software engineering, a design pattern is a general reusable solution to a commonly occurring problem in software design. A design pattern is not a finished design that can be transformed directly into code. It is a description or template for how to solve a problem that can be used in many different situations. Object-oriented design patterns typically show relationships and interactions between classes or objects, without specifying the final application classes or objects that are involved. Here I will introduce 3 design patterns. More design patterns are available in my future posts.
1. Singleton
1.1 Pattern Goal
This Pattern make an object to be created once in whole application life cycle. If you want any thread or request uses and shares only one instance of indicated object you can apply this pattern. This pattern deals with concurrency problem of critical sections in class methods. Thus, take care of concurrency whenever you use this pattern as a solution.
1.2 Pattern Detail
To make a class have single object in application scope, we should make the constructor of the class, private. This prevents of creating the class.
public class TestClass{
private TestClass() {
}
}
public class TestClass {
private static TestClass testClass;
private TestClass() {
}
public static TestClass getInstance() {
if (testClass == null) {
testClass = new TestClass();
}
return testClass;
}
}
...
TestClass testClass = TestClass.getInstance();
testClass.customMethod();
...
We want to know how many times a button is clicked. Here is the class to save click count.
public class ClickButton {
private static ClickButton clickButton;
Integer clickCount;
private ClickButton() {
clickCount = 0;
}
public static ClickButton getInstance() {
if (clickButton == null) {
clickButton = new ClickButton();
}
return clickButton;
}
public void click() {
synchronized (clickCount) {
clickButton.clickCount++;
}
}
public Integer getClickCount() {
return clickButton.clickCount;
}
}
@Controller
@Scope("prototype")
@RequestMapping("/button")
public class ButtonController {
...
@RequestMapping("/click")
public String click(@ModelAttribute("button")ClickButton clickButton, HttpServletRequest request) {
clickButton.click();
request.setAttribute("clickcoutn", clickButton.getClickCount());
return "button.view";
}
...
}
1.1 Pattern Goal
Attach additional responsibilities to an object dynamically keeping the same interface. Decorators provide a flexible alternative to subclassing for extending functionality. On the other hands we can decorate a class dynamically. For example a simple coffee class has only coffee as ingredients. But we will be able to add milk, sugar, ... to it dynamically when apply this patter.
1.2 Pattern Detail
We should make an interface and a simple form of class implementing the interface. Another class is decorated class implementing the interface. The decorator class should contains a protected object of the interface and initiate it in its constructor. In implementation of the interface methods, We should just call and return the related method of the protected field. The decorator class should be an abstract class to prevent directed usage.
Now you can create other classes extending decorator class. Then override the interface methods of the decorator class in your custom class and do any decoration to the methods. Here is the pattern structure:
1.Interface:
public interface TestClass{
Object testMethod();
}
public class Simple
TestClass
implements
TestClass
{
public Object
testMethod
() {
return Do something;
}
}
public abstract class Decorator
TestClass
implements
TestClass
{
protected
TestClass
testClass
;
public
Decorator
TestClass
(
TestClass
testClass
) {
this.
testClass
=
testClass
;
}
public
Object
testMethod
() {
return
testClass
.
testMethod
();
}
}
public class CustomTestClass1 extends
Decorator
TestClass
{
public
CustomTestClass
1(
TestClass
testClass
) {
super(
testClass
);
}
@Override
public Object
testMethod
() {
Object test = super.
testMethod
();
do something with test
return
test
;
}
}
public class CustomTestClass2 extends DecoratorTestClass{
public CustomTestClass2(TestClass testClass) {
super(testClass);
}
@Override
public Object testMethod() {
Object test = super.testMethod();
do something with test
return test;
}
}
...
public class CustomTestClassN extends DecoratorTestClass{
public CustomTestClassN(TestClass testClass) {
super(testClass);
}
@Override
public Object testMethod() {
Object test = super.testMethod();
do something with test
return test;
}
}
public class TestController {
public Object TestMethod(){
TestClass test = new
CustomTestClass2(new
CustomTestClass5(new
CustomTestClass7(new
Simple
TestClass
())
)
)
;
return test.
testMethod();
}
}
1.3 Pattern Sample
House List example is a sample that works with house class. House class has two methods including getFacilityLIST() and getPrice(). I'm going to apply decorator pattern to these two methods. Some facilities will be apply to the basic house and its price gets more dynamically. Here is the class diagram:
and here is the source code:
1. Interface:
public interface House {
List<String> getFacilityLIST();
Long getPrice();
}
public class SimpleHouse implements House{
public List<String> getFacilityLIST() {
List<String> facilityList = new ArrayList();
facilityList.add("Building");
facilityList.add("Restroom");
facilityList.add("Kitchen");
facilityList.add("Salon");
return facilityList;
}
public Long getPrice() {
return 1000l;
}
}
public abstract class DecoratorHouse implements House{
protected House decoratedHouse;
public DecoratorHouse(House decoratedHouse) {
this.decoratedHouse = decoratedHouse;
}
public List<String> getFacilityLIST() {
return decoratedHouse.getFacilityLIST();
}
public Long getPrice() {
return decoratedHouse.getPrice();
}
}
public class SingleRoomHouse extends DecoratorHouse{
public SingleRoomHouse(House decoratedHouse) {
super(decoratedHouse);
}
@Override
public List<String> getFacilityLIST() {
List<String> facilityList = super.getFacilityLIST();
facilityList.add("1 Room");
return facilityList;
}
@Override
public Long getPrice() {
return super.getPrice() + 200l;
}
}
public class DoubleRoomHouse extends DecoratorHouse{
public DoubleRoomHouse(House decoratedHouse) {
super(decoratedHouse);
}
@Override
public List<String> getFacilityLIST() {
List<String> facilityList = super.getFacilityLIST();
facilityList.add("2 Rooms");
return facilityList;
}
@Override
public Long getPrice() {
return super.getPrice() + 400l;
}
}
public class CompleteHouse extends DecoratorHouse{
public CompleteHouse(House decoratedHouse) {
super(decoratedHouse);
}
@Override
public List<String> getFacilityLIST() {
List<String> facilityList = super.getFacilityLIST();
facilityList.add("Gardened Yard");
facilityList.add("Car Parking");
return facilityList;
}
@Override
public Long getPrice() {
return super.getPrice() + 1000l;
}
}
public class ModernHouse extends DecoratorHouse{
public ModernHouse(House decoratedHouse) {
super(decoratedHouse);
}
@Override
public List<String> getFacilityLIST() {
List<String> facilityList = super.getFacilityLIST();
facilityList.add("Closet");
facilityList.add("Pool");
return facilityList;
}
@Override
public Long getPrice() {
return super.getPrice() + 1000l;
}
}
3. Immutable Object
1.1 Pattern Goal
To make an object read only or even make an object read only in some places of you application, you can apply this pattern to you classes.
1.2 Pattern Detail
First of all you should make a wrapper to your class. We call this wrapper class, Immutable Class. The Immutable Class should have a private final field with the indicated class data type and initiate it in the constructor. Then make a getter for that. In the getter method you should return a clone of the field. This make a new instance of the object and this make the object read only. Whenever you get the object from this method a new instance will be make so the object which is passed from the constructor will stay safe and won't be changed.
Note: Your Object should be cloneable
Take a look to these codes:
Base class:
public class TestClass implements Cloneable{
String field1;
public
TestClass
(String
field1
) {
this.
field1
=
field1
;
}
public String get
Field1
() {
return name;
}
public void setF
ield1
(String
field1
) {
this.
field1
=
field1
;
}
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class ImmutableTestClass {
private final
TestClass testClass
;
public
ImmutableTestClass
(Student
testClass
) {
this.
testClass
=
testClass
;
}
public
testClass
getTestClass() throws CloneNotSupportedException {
return (
TestClass
)
testClass
.clone();
}
}
1.3 Pattern Sample
Student class is an entity bean class. I will make it Immutable and show you if you change the object, even manually, the major object will be never changed. Here is the class diagram:
Entity Bean:
public class Student implements Cloneable{
String name;
String stNo;
Float gpa;
public Student(String name, String stNo, Float gpa) {
this.name = name;
this.stNo = stNo;
this.gpa = gpa;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getStNo() {
return stNo;
}
public void setStNo(String stNo) {
this.stNo = stNo;
}
public Float getGpa() {
return gpa;
}
public void setGpa(Float gpa) {
this.gpa = gpa;
}
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class ImmutableStudent {
private final Student student;
public ImmutableStudent(Student student) {
this.student = student;
}
public Student getStudent() throws CloneNotSupportedException {
return (Student) student.clone();
}
}
@Controller
@Scope("prototype")
@RequestMapping("/student")
public class StudentController {
@ModelAttribute("student")
public ImmutableStudent studentModel() {
return new ImmutableStudent(new Student("Mostafa Rastgar", "2020041251", 15.2f));
}
@RequestMapping("/view")
public String view() {
return "student.view";
}
@RequestMapping("/save")
public String save(@ModelAttribute("student") ImmutableStudent immutableStudent, @RequestParam(value="student.name", required = true) String name, @RequestParam(value="student.stNo", required = true) String stNo, @RequestParam(value="student.gpa", required = true) Float gpa, HttpServletRequest request) throws CloneNotSupportedException {
Student student = immutableStudent.getStudent();
student.setName(name);
student.setStNo(stNo);
student.setGpa(gpa);
request.setAttribute("studentParam", student);
return "student.view";
}
}
Source Code
You can download those 3 samples from here. After the deployment the start page is: http://localhost:8080/button/view.html
all rights reserved by Mostafa Rastgar and Programmer Assistant weblog
4 comments:
Hi,
In singleton pattern maybe it's better to synchronized method instead of static field before you screw the class :D WYT?
public synchronized void click(){
clickBtton.clickCount++;
}
dude, ur exactly right
one more thing, I'm just wondering in immutable pattern why do u implements Cloneable interface in TestClass cause every class has clone() method as an object is it really necessary ?
I implement Cloneable and override clone() method, because to make a class cloneable we should do it. clone method is a protected method of Object class. To make it public we should override it. If a class does not implements Cloneable, exception will be raised in clone() method.
Post a Comment