© Adam L. Davis 2020
A. L. DavisModern Programming Made Easyhttps://doi.org/10.1007/978-1-4842-5569-8_9

9. Design Patterns

Adam L. Davis1 
(1)
Oviedo, FL, USA
 

In object-oriented programming (OOP), design patterns are useful organizations of state and behavior that make your code more readable, testable, and extensible. Now that you understand classes, inheritance, objects, and the basics of programming, let’s go over some common design patterns—common ways of arranging application code.

Observer

The observer pattern allows you to broadcast information from one class to many others, without them having to know about each other directly (low coupling).

It is often used with events. For example, the KeyListener, MouseListener, and many other “Listener” interfaces in Java Swing, which is a built-in part of the JDK for building desktop applications, implement the observer pattern and use events.

Another example of this pattern is the Observable class and Observer interfaces supplied in Java. Here is a simple example that simply repeats the same event forever:
 1   import java.util.Observable;
 2
 3   public class EventSource extends Observable implements Runnable {
 4       @Override
 5       public void run() {
 6           while  (true) {
 7               notifyObservers("event");
 8           }
 9       }
10   }

Although the event is a String in this example, it could be of any type.

The following class implements the Observer interface and prints out any events of type String:
 1   import java.util.Observable;
 2   import java.util.Observer;
 3
 4   public class StringObserver implements Observer {
 5       public void update(Observable obj, Object event) {
 6           if (event instanceof String) {
 7               System.out.println(" Received Response: " + event );
 8           }
 9       }
10   }
To run this example, write the following code within your main method:
1   final EventSource eventSource = new EventSource();
2   // create an observer
3   final StringObserver stringObserver = new StringObserver();
4   // subscribe the observer to the event source
5   eventSource.addObserver(stringObserver);
6   // starts the event thread
7   Thread thread = new  Thread(eventSource);
8   thread.start();
Although you are only adding one observer on line 5, you could add any number of observers without changing the code of EventSource. This is what is meant by low coupling.

MVC

Model–view–controller (MVC) is possibly the most popular software design pattern (Figure 9-1). As the name suggests, it consists of three major parts:
  • Model: The data or information being shown and manipulated

  • View: What actually defines how the model is shown to the user

  • Controller: Defines how actions can manipulate the model

../images/435475_2_En_9_Chapter/435475_2_En_9_Fig1_HTML.jpg
Figure 9-1

Model–view–controller

This design allows the controller, model, and view to know very little about each other. This reduces coupling—the degree to which different components of the software rely on other components. When you have low coupling, your software is easier to understand and easier to extend.

We will look at a great example of MVC in the chapter about web applications and Grails (Chapter 17).

DSL

A domain-specific language (DSL) is a custom programming language made for a specific domain. For example, you can think of HTML as a DSL for displaying web pages.

Some languages allow you such freedom that you can create a DSL inside the language. For example, Groovy and Scala allow you to override the math symbols (+, -, etc.). The other freedoms of these languages (optional parentheses and semicolons) allow for DSL-like interfaces. We call these DSL-like interfaces fluent interfaces.

You can also create fluent interfaces in Java and other languages. The following sections discuss building a DSL with Groovy.

Closures

Within Groovy, you can take a block of code (a closure) as a parameter and then call it, using a local variable as a delegate—which makes all methods of that object directly referable within the closure. For example, imagine that you have the following code for sending SMS texts:
 1   class SMS {
 2           def from(String fromNumber) {
 3                   // set the from
 4           }
 5           def to(String toNumber) {
 6                   // set the to
 7           }
 8           def body(String body) {
 9                   // set the body of text
10           }
11           def send() {
12                   // send the text.
13           }
14   }
In Java, you’d have to use this the following way (notice the repetition):
1   SMS m = new  SMS();
2   m.from("555-432-1234");
3   m.to("555-678-4321");
4   m.body("Hey there!");
5   m.send();
In Groovy, you can add the following static method to the SMS class for DSL-like usage (it takes a closure, sets the delegate to an instance of the SMS class, calls the block, and then calls send on the SMS instance):
1   def static send(Closure block) {
2           SMS m = new SMS()
3           block.delegate = m
4           block()
5           m.send()
6   }
This sets the SMS object as a delegate for the block, so that methods are forwarded to it. With this you can now do the following:
1   SMS.send {
2           from '555-432-1234'
3           to '555-678-4321'
4           body 'Hey there!'
5   }

Overriding Operators

In Scala or Groovy, you could create a DSL for calculating speeds with specific units, such as meters per second.
1   val time =  20 seconds
2   val dist =  155 meters
3   val speed =  dist / time
4   println(speed.value) //  7.75

By overriding operators, you can constrain users of your DSL to reduce errors. For example, accidentally typing time/dist here would cause a compilation error in this DSL.

Here’s how you would define this DSL in Scala:
 1   class Second(val value: Float) {}
 2   class MeterPerSecond(val  value:  Float) {}
 3   class Meter(val value: Float) {
 4     def /(sec: Second) = {
 5       new MeterPerSecond(value / sec.value)
 6     }
 7   }
 8   class EnhancedFloat(value: Float) {
 9     def seconds =  {
10       new   Second(value)
11     }
12     def  meters =  {
13       new  Meter(value)
14     }
15   }
16   implicit  def  enhanceFloat(f:  Float) =  new  EnhancedFloat(f)

../images/435475_2_En_9_Chapter/435475_2_En_9_Figa_HTML.jpg Scala has the implicit keyword, which allows the compiler to do implicit conversions for you.

Notice how the divide / operator is defined just like any other method using the def keyword.

../images/435475_2_En_9_Chapter/435475_2_En_9_Figb_HTML.jpg In Groovy, you overload operators by defining methods with special names1 such as plus, minus, multiply, div, etc.

Actors

The actor design pattern is a useful pattern for developing concurrent software. In this pattern, each actor executes in its own thread and manipulates its own data. The data cannot be manipulated by anyone else. Messages are passed between actors to cause them to change data (Figure 9-2).
../images/435475_2_En_9_Chapter/435475_2_En_9_Fig2_HTML.jpg
Figure 9-2

Actors

Note

When data can only be changed by one thread at a time, we call it thread-safe. If multiple threads modify the same data at the same time, this is very bad (it can cause exceptions).

There are many implementations of this pattern that you can use, including the following:
  • Akka2

  • Jetlang3

  • FunctionalJava4

  • GPars5

Chain of Responsibility

The Chain of Responsibility pattern allows you to split code up that will handle different cases without each part knowing about all the other parts.

For example, this could be a useful pattern when designing a web application that takes many different actions depending on the URL the user visits. In this case you could have a WebHandler interface with a method that may or may not handle that URL and returns a String:
1   public interface WebHandler {
2       String handle(String url);
3       void setNext(WebHandler next);
4   }
Then you can implement that interface, and call on the next handler in the chain if you do not handle that URL:
1   public class ZombieHandler implements WebHandler {
2       WebHandler next;
3       public String handle(String url) {
4           if (url.endsWith("/zombie")) return "Zombie!";
5           else return next.handle(url);
6       }
7       public void setNext(WebHandler next) {this.next = next;}
8   }

This class would only return a value if the URL ended with /zombie. Otherwise, it delegates to the next handler in the chain.

Facade

The Facade pattern allows you to hide the complexity of a larger system under a simpler design. For example, you could have one class with some methods that call the methods of many other classes.

Let’s take the previous example and create a facade that handles an incoming web URL without needing to reference any specific WebHandler implementations. Create a class named WebFacade:
1  public class WebFacade {
2    public String handle(String url) {
3        WebHandler firstHandler = new ZombieHandler();
4        WebHandler secondHandler = new DragonHandler();
5        WebHandler finalHandler = new DefaultHandler();
6        firstHandler.setNext(secondHandler);
7        secondHandler.setNext(finalHandler);
8        return firstHandler.handle(url);
9    }
10 }

The WebFacade creates all of our handler classes, wires them together (calling setNext), and finally returns a value by calling the handle method of the first WebHandler.

The user of WebFacade wouldn’t need to know anything about how the URL was handled. This is the usefulness of the Facade pattern.

Summary

In this chapter, you learned about some common design patterns and ways of designing applications. This is not a comprehensive list of design patterns. For more information about object-oriented design patterns, check out oodesign.​com.6 In this chapter, you learned
  • What a DSL is and how to write one

  • Observer, MVC, Chain of Responsibility, and Facade patterns

  • Actor pattern for handling concurrency

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset