Design Patterns In Java
What’s a design pattern?
Design patterns are classical solutions to most commonly occurring problems in software design. They are like instant blueprints that you can customize to solve a recurring design problem in your code/program.
You can’t just find a pattern and copy it into your program or code, the way you can with off-the-shelf functions or libraries. The pattern is not an identified piece of code, but a general idea for solving a particular problem. You can follow the pattern details and implement a solution that suits the actuality of your own program.
Patterns are often demented with algorithms because both ideas describe typical solutions to some known problems. While an algorithm always defines a clear set of actions that can be used to achieve some goal, we can say the pattern is a more high-level description of a solution. The code of the same pattern applied to two distinct programs may be different.
If we make an analogy to an algorithm is just like a cooking recipe: both have clear steps to achieve a goal. On the other hand, a pattern is more like a blueprint: you can clearly see what the result and its features are, but the exact order of implementation depends upon you.
What does the pattern consist of?
Most patterns are narrated very formally so people can reproduce them in many conditions. Here are the segments that are usually present in a pattern description:
The intent of the pattern briefly describes both the problem and the solution.
Motivation additionally explains the problem and the solution the pattern makes possible.
The structure of classes shows each part of the pattern and how they are related.
The code example in one of the popular programming languages makes it easier to grasp the idea behind the pattern.
Some pattern catalogs list other useful details, such as the applicability of the pattern, implementation steps and relations with other patterns.
History of patterns
That’s a good, but not a very precise, question. Design patterns aren’t unclear, advanced concepts—quite the opposite. Patterns are classical solutions to commonly occurring problems in object-oriented design. When a solution occurs over and over in various projects, someone eventually puts a name to it and describes the solution in detail. That’s basically how a pattern gets discovered.
The concept of patterns was initially described by Christopher Alexander in A Pattern Language: Towns, Buildings, Construction. The book narrates a “language” for designing the urban environment. The units of this language are patterns. They may describe how high windows should be, how large green areas in a neighborhood are supposed to be, how many levels a building should have and so on.
The concept was picked up by four authors: Erich Gamma, John Vlissides, Ralph Johnson, and Richard Helm. In the year 1995, they published one book named Design Patterns: Elements of Reusable Object-Oriented Software, in which they applied the concept of design patterns to programming. The book talks about 23 patterns solving various problems of object-oriented design and became a best-seller very quickly. Due to its lengthy name, people started to call it “the book by the gang of four” which was soon shortened to simply “the GoF book”.
Since then, a number of other object-oriented patterns have been discovered. The “pattern approach” became very popular in another programming area, so lots of other patterns now exist outside of object-oriented design as well.
Why you should learn patterns?
The truth is that you might manage to work as a software developer for many years without having knowledge about a single design pattern. A lot of programmers do just that. Even in that case, though, you might be applying some patterns without even knowing it. So why would anyone spend time learning them?
Design patterns are a toolkit of tried and tested solutions to common problems that occur in software design. Even if you never face these problems, having knowledge about design patterns is still useful because it teaches you how to solve all sorts of problems using principles of object-oriented design.
Design patterns define a common language that you and your project mates can use to communicate more efficiently. You can say, “Oh, just use a Singleton for that,” and everyone will understand the concept behind your suggestion. No need to explain what a singleton is if you know the pattern and its name
Classification of patterns
Design patterns varied by their complexity, level of detail and scale of applicability to the entire system that is being designed. let’s understand analogy to road construction: you can make an intersection safer by either installing some traffic lights or constructing an entire multi-level interchange with underground passages for pedestrians.
The most fundamental and low-level patterns are often called idioms. They are usually applied only to a single programming language.
Architectural patterns are the most universal and high-level patterns. Programmers can implement these patterns in virtually any language. The architectural patterns can be used to design the architecture of an entire application, Unlike other patterns.
Creational patterns supply object creation systems that increase flexibility and reuse of existing code.
Structural patterns describe how to assemble objects and classes into larger structures while keeping the structures flexible and efficient.
Behavioral patterns take care of effective communication and the assignment of responsibilities between objects.
Let’s see One Example of Each Design Pattern.
- Creational Design Pattern
Factory Method is a creational design pattern that provides an interface for creating objects in a Parent class but allows Child classes to change the type of objects that will be created.
Imagine that you’re creating an application for logistics management. The Initial version of your application can only handle or manage transportation by trucks, so a large amount of your code lives inside the Truck class.
After a while, your app becomes pretty popular. Each day you receive a number of requests from sea transportation companies to integrate sea logistics into the app.
Great news, right? But how about the code? At present, most of your code is written inside the Truck class. Adding Ships into the application would require making changes to the entire codebase. Moreover, if later you decide to add another type of transportation to the app, you will probably need to make all of these changes again.
As a result, you will end up with pretty nasty code, riddled with conditionals that switch the app’s behavior depending on the class of transportation objects.
The Factory Method pattern recommends that you replace direct object construction calls (using the new operator) with calls to a special factory method. Don’t get confused: the objects are still created via the new operator, but it’s being called from within the factory method. Instances or Objects returned by a factory method is often referred to as “products.”
At the first point, this change may look useless: we just shifted the constructor call from one part of the program to another. However, imagine this: now you can easily override the factory method in a subclass and change the class of products being created by the method.
There’s a small limitation though: subclasses may return different types of products only if these products have a common base class or interface. Also, the factory method in the Child class should have its return type declared as this interface.
For example, both Truck and Ship classes should implement the Transport interface, which declares a method called to deliver. Every class will implement this method differently: ships deliver cargo by sea, trucks deliver cargo by land. The factory method in the RoadLogistics class returns truck instances or objects, whereas the factory method in the SeaLogistics class returns ship instances or objects.
The program that uses the factory method (often called the client code) doesn’t see a difference between the actual products returned by various subclasses. The client knows that all transport objects are supposed to have the delivery method, but exactly how it works isn’t important to the client.
B.Structural Design Pattern
The adapter pattern is a structural design pattern that allows objects or instances with irreconcilable interfaces to communicate.
Imagine that you’re creating a stock market monitoring application. The app downloads the stock data in XML format from multiple sources and then displays nice-looking charts and diagrams for the user.
At some point, you decide to improve the application by integrating a smart 3rd-party analytics library. But there’s a problem: the analytics library only works with data in JSON format.
You could change the library to work with XML format data. However, this might shatter some existing code that relies on the library. And worse, you might not have access to the library’s source code in the first place, making this approach impossible to use.
You can create an adapter. This is a special object that converts the interface of one object so that another object can interpret it.
An adapter wraps one of the objects to hide the complications of conversion happening behind the scenes. The wrapped object isn’t even aware of the adapter. To understand this let us consider the one example: you can wrap an object that works in meters and kilometers with an adapter that converts all of the data to imperial units such as feet and miles.
Adapters can not only convert data into various formats but can also help objects with different interfaces to communicate with each other. Here’s how it works:
The adapter gets an interface, adaptable with one of the existing objects.
Using this interface, the existing object can safely invoke the adapter’s methods.
After receiving a call, the adapter passes the request to the second object, but in a format and order that the second object expects.
Sometimes it’s even possible to create a two-way adapter that can convert the calls in both directions.
Let’s get back to our stock market application. To overcome the difficulty of incompatible formats, you can create XML-to-JSON adapters for every class of the analytics library that your code works with directly. Then you adjust your code to collaborate with the library only via these adapters. When an adapter receives a call, it interprets the incoming XML data into a JSON structure and passes the call to the appropriate methods of a wrapped analytics object.
When you travel from the United States of America to Europe for the first time, you may get a surprise when trying to charge your laptop. The power plug and sockets standards are distinct in various countries. That is the reason why your US plug won’t fit a German socket. The issue can be solved by using a power plug adapter that has the American-style socket and the European-style plug.
C. Behavioral Design Pattern
1.Iterator Design Pattern
Iterator pattern is a behavioral design and one of the most commonly used in collection pattern that lets you traverse across instances of a collection without revealing its underlying representation (list, stack, tree, etc.).
Collections are one of the most commonly used data types in programming. Nonetheless, a collection acts as a container to hold a group of objects.
Most collections store their elements or objects in simple lists. However, some of them are based on trees, stacks, graphs, and some other complex data structures.
But no matter how a collection is structured, it must supply some way of accessing its elements or Objects so that other code can use these elements. There should be some way to go travel each element of the collection without accessing the same elements over and over.
If you have a collection based on a list This may sound like an easy job for you. You just loop over all of the elements or objects. But what if you want to sequentially traverse elements of a complex data structure, such as a tree? For example, one day you might be just fine with the breadth-first traversal. Yet the next day you might require. And the next week’s depth-first traversal of a tree, you may need something else, like random access to the tree elements.
Adding more and more traversal algorithms to the collection gradually unclear its primary responsibility, which is efficient data storage. Additionally, some algorithms might be customized for a specific application, so including them into a generic collection class would be uncanny.
On the other hand, the client code that is supposed to work with different types of collections may not even care how they store their elements. However, since collections all provide different ways of accessing their elements, you have no option other than to couple your code to the specific collection classes.
The core idea of the Iterator pattern is to extract the traversal behavior of a collection into a separate object called an iterator.
position of an element and how many elements are left to traverse. Because of this, a number of iterators can go through the same collection at the same time, independently of each other.
Usually, iterators provide one primary method for retrieving elements of the collection. The client can keep running this method until it doesn’t return anything, which means that the iterator has traversed all of the elements or objects.
All iterators must implement the common interface. This makes the client code compatible with any type of collection or any traversal algorithm as long as there’s a proper iterator. If you want another way to traverse a collection, you just create a new iterator class, without having to change the collection or the client.
You plan to visit a new city like Rome for a few days and visit all of its main sights and attractions. But once you are there, you could waste a lot of time walking in circles, unable to find even the Colosseum.
On the other hand, what you can do is, you could buy a virtual guide app for your smartphone and use it for navigation. It’s smart and inexpensive, and you could be staying in some interesting places for as long as you want.
A third option is that you could spend some of the trip’s budget and hire a local guide who knows the city like the back of his hand. The guide would be able to tailor the tour to your preference, show you every attraction and tell a lot of exciting stories. That’ll be even more fun; but, alas, more expensive, too.
All of these options—the random directions born in your head, the smartphone navigator or the human guide—act as iterators over the vast collection of sights and attractions located in Rome.
Shah Rukh Patwekar | Software Trainer
SevenMentor Pvt Ltd.
Call the Trainer and Book your free demo Class for JAVA now!!!
© Copyright 2020 | Sevenmentor Pvt Ltd.