The most commonly used design patterns
Factory mode
This type of design pattern belongs to the creation pattern. When we create objects, we do not expose the creation logic to the client, and we point to the newly created objects by using a common interface.
Intention: define an interface to create an object, let its subclass decide which factory class to instantiate by itself, and factory mode delays its creation process to subclass.
Singleton mode
This type of design pattern is a creation pattern, which provides the best way to create objects. This pattern involves a single class that is responsible for creating its own objects, while ensuring that only a single object is created. This class provides a way to access its unique object, which can be accessed directly without instantiating the object of this class.
Intent: ensure that a class has only one instance, and provide a global access point to access it.
Main solution: a global class is frequently created and destroyed.
When to use: when you want to control the number of instances and save system resources.
How to solve: judge whether the system already has this single instance. If there is one, return it. If not, create it. The constructor is private.
Adapter mode
As a bridge between two incompatible interfaces. This type of design pattern belongs to structural pattern, which combines the functions of two independent interfaces. This pattern involves a single class that is responsible for adding independent or incompatible interface functions.
Main solution: in the software system, it is often necessary to put some "existing objects" into the new environment, and the interface required by the new environment is not satisfied by the existing objects.
Code implementation:
// Media player interface public interface MediaPlayer { public void play(String audioType, String fileName); } // More advanced media player interface public interface AdvancedMediaPlayer { public void playVlc(String fileName); public void playMp4(String fileName); } // VIC player (realize advanced media player interface) public class VlcPlayer implements AdvancedMediaPlayer{ @Override public void playVlc(String fileName) { System.out.println("Playing vlc file. Name: "+ fileName); } @Override public void playMp4(String fileName) { //Do nothing } } // MP4 player (realize media player interface) public class Mp4Player implements AdvancedMediaPlayer{ @Override public void playVlc(String fileName) { //Do nothing } @Override public void playMp4(String fileName) { System.out.println("Playing mp4 file. Name: "+ fileName); } } // Adapter class for the normal media player interface. public class MediaAdapter implements MediaPlayer { AdvancedMediaPlayer advancedMusicPlayer; public MediaAdapter(String audioType){ if(audioType.equalsIgnoreCase("vlc") ){ advancedMusicPlayer = new VlcPlayer(); } else if (audioType.equalsIgnoreCase("mp4")){ advancedMusicPlayer = new Mp4Player(); } } @Override public void play(String audioType, String fileName) { if(audioType.equalsIgnoreCase("vlc")){ advancedMusicPlayer.playVlc(fileName); }else if(audioType.equalsIgnoreCase("mp4")){ advancedMusicPlayer.playMp4(fileName); } } }
Decorator mode
Further encapsulate the existing operator logic, and add additional functions during the period. For example, the IO flow uses the decorator mode. When users use it, they can assemble it at will to achieve the desired results.
Code implementation:
//Shape interface public interface Shape { void draw(); } //Rectangle class (implement shape interface) public class Rectangle implements Shape { @Override public void draw() { System.out.println("Shape: Rectangle"); } } //Circular class (implement shape interface) public class Circle implements Shape { @Override public void draw() { System.out.println("Shape: Circle"); } } //Abstract decoration class of shape class public abstract class ShapeDecorator implements Shape { protected Shape decoratedShape; public ShapeDecorator(Shape decoratedShape){ this.decoratedShape = decoratedShape; } public void draw(){ decoratedShape.draw(); } } //Extended abstract decoration class public class RedShapeDecorator extends ShapeDecorator { public RedShapeDecorator(Shape decoratedShape) { super(decoratedShape); } @Override public void draw() { decoratedShape.draw(); setRedBorder(decoratedShape); } private void setRedBorder(Shape decoratedShape){ System.out.println("Border Color: Red"); } } public class DecoratorPatternDemo { public static void main(String[] args) { Shape circle = new Circle(); ShapeDecorator redCircle = new RedShapeDecorator(new Circle()); ShapeDecorator redRectangle = new RedShapeDecorator(new Rectangle()); System.out.println("Circle with normal border"); circle.draw(); System.out.println("\nCircle of red border"); redCircle.draw(); System.out.println("\nRectangle of red border"); redRectangle.draw(); } }
Output results:
Circle with normal border
Shape: Circle
Circle of red border
Shape: Circle
Border Color: Red
Rectangle of red border
Shape: Rectangle
Border Color: Red
proxy pattern
In the proxy pattern, one class represents the function of another class. This type of design pattern belongs to the structural pattern. In the proxy pattern, objects with existing objects are created to provide functional interfaces to the outside world.
Intent: provide a proxy for other objects to control access to this object.
When to use: want to do some control when accessing a class.
How to solve: add the middle layer.
Key code: combination of implementation and proxied class.
Code implementation:
//Picture interface public interface Image { void display(); } //Red picture class (implementation of red picture interface) public class RealImage implements Image { private String fileName; public RealImage(String fileName){ this.fileName = fileName; loadFromDisk(fileName); } @Override public void display() { System.out.println("Displaying " + fileName); } private void loadFromDisk(String fileName){ System.out.println("Loading " + fileName); } } //Picture interface proxy class (implementing picture interface) public class ProxyImage implements Image{ private RealImage realImage; private String fileName; public ProxyImage(String fileName){ this.fileName = fileName; } @Override public void display() { if(realImage == null){ realImage = new RealImage(fileName); } realImage.display(); } } //test public class ProxyPatternDemo { public static void main(String[] args) { Image image = new ProxyImage("wang.jpg"); // Pictures will be loaded from disk image.display(); // Picture does not need to be loaded from disk (image object has been created) image.display(); } }
Output results:
Loading wang.jpg
Displaying wang.jpg
Displaying wang.jpg