- Structural design patterns involve how to assemble classes and objects to achieve a larger structure.
- Structured class pattern uses inheritance mechanism to combine interfaces or implementations.
1. Agent mode
Introduction:
- Proxy Pattern uses one class to represent the functions of another class, and objects with existing objects to provide functional interfaces to the outside world
- give an example:
- Chatting with MM on the Internet always starts with "hi, hello" and "where are you from?" "How old are you?" "How tall?" These words are really annoying. Write a program as my Proxy. All those who receive these words have set their own answers, and notify me when they receive other words. How cool.
- Agent mode:
- Proxy mode provides a proxy object for an object, and the proxy object controls the reference to the source object.
- An agent is a person or an organization acting on behalf of another person or an organization. In some cases, the client does not want or cannot directly reference an object. The proxy object can directly mediate between the client and the target object.
- The client cannot distinguish the proxy subject object from the real subject object. The proxy mode may not know the real proxy object, but only hold an interface of the proxy object. At this time, the proxy object cannot create the proxy object, and the proxy object must be created and passed in by other roles of the system.
- Intent:
- Provide a proxy for other objects to control access to this object
- Main solutions:
- Problems caused by direct access to objects, for example: the object to be accessed is on a remote machine
- In object-oriented systems, direct access to some objects will bring a lot of trouble to users or system structure for some reasons (such as high cost of object creation, or some operations need security control, or need out of process access). We can add an access layer to this object when accessing this object
Applicable scenarios:
- To buy a train ticket, you don't have to buy it at the railway station. You can also go to the selling point
- A check or certificate of deposit is the agent of the funds in the account. The check is used to replace cash in market transactions and provide control over the funds on the issuer's account number
- spring aop
- Remote agent
- Virtual agent
- Copy on write agent
- Protect or Access agent
- Cache proxy
- Firewall agent
- Synchronization agent
- Smart Reference proxy
Structure:
- Define an Image interface and an entity class that implements the Image interface
- Define proxy class ProxyImage to reduce the memory occupation of RealImage object loading
- The definition class ProxyPatternDemo uses ProxyImage to obtain the Image object to be loaded and display it as required
Code implementation:
1. Create an interface and implement it
public interface Image { void display(); } 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); } } 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(); } }
2. When requested, use ProxyImage to get the object of RealImage class
public class ProxyPatternDemo { public static void main(String[] args) { Image image = new ProxyImage("test_10mb.jpg"); //The image will be loaded from disk image.display(); System.out.println(""); //The image will not load from disk image.display(); } }
Dynamic agent
What is the difference between dynamic and static agents? What scenarios are used? Static agents usually only represent one class, while dynamic agents represent multiple implementation classes under one interface. Static agents know what to proxy in advance, while dynamic agents do not know what to proxy. Only at runtime. Dynamic agent is an implementation JDK of InvocationHandler Interfaced invoke Method, but note that the proxy is the interface. That is, the interface that your business class must implement proxy Inside newProxyInstance Get the proxy object. There is also a dynamic proxy CGLIB,The proxy is a class, which does not need the business class to inherit the interface. The interface is realized through the derived subclass. The purpose of modifying the class is achieved by dynamically modifying the bytecode at runtime. AOP Programming is based on dynamic agents, such as spring Frame.
2. Adapter design pattern
Introduction:
-
Adapter Pattern is a bridge between two incompatible interfaces.
-
The adapter pattern involves a single class that is responsible for adding independent or incompatible interface functions
-
give an example:
- At a friend's party, I met a beautiful Sarah from Hong Kong, but I can't speak Cantonese. She can't speak Mandarin, so I had to turn to my friend kent. As the Adapter between me and Sarah, he let me talk with Sarah (I don't know if he will play with me)
- The card reader is used as an adapter between the memory card and the notebook. You insert the memory card into the card reader, and then insert the card reader into the notebook, so that you can read the memory card through the notebook
-
Adapter mode:
- The interface of a class is transformed into another interface expected by the client, so that the two classes that cannot work together due to interface mismatch can work together.
- The adaptation class can return an appropriate instance to the client according to the parameters.
-
Intent:
Convert the interface of a class into another interface that the customer wants. The adapter pattern allows classes that cannot work together because of interface incompatibility to work together
-
Main solutions:
The main solution is that in the software system, some "existing objects" often need to be put into the new environment, and the interface required by the new environment cannot be met by the existing objects
-
When to use:
- The system needs to use existing classes, and such interfaces do not meet the needs of the system
- You want to create a reusable class to work with some classes that are not closely related to each other, including some classes that may be introduced in the future. These source classes do not necessarily have consistent interfaces
- Insert one class into another class family through interface conversion. (for example, tigers and birds, now there is a flying tiger. Without increasing the demand of entities, an adapter is added to contain a tiger object and realize the flying interface.)
Applicable scenarios:
- American electric appliance 110V, Chinese 220V, there must be an adapter to convert 110V into 220V
- JAVA JDK 1.1 provides the Enumeration interface, while 1.2 provides the Iterator interface. If you want to use the 1.2 JDK, you need to convert the Enumeration interface of the previous system into the Iterator interface. At this time, you need the adapter mode
- Running WINDOWS program on LINUX
- jdbc in JAVA
- If you are motivated to modify the interface of a functioning system, you should consider using the adapter mode.
Structure:
- MediaPlayer interface and an entity class AudioPlayer that implements the MediaPlayer interface. By default, AudioPlayer can play mp3 format audio files
- Interface AdvancedMediaPlayer and entity classes that implement the AdvancedMediaPlayer interface. This class can play files in vlc and mp4 formats
- Let AudioPlayer play audio files in other formats. To realize this function, we need to create an adapter class MediaAdapter that implements the MediaPlayer interface and use the AdvancedMediaPlayer object to play the required format
- AudioPlayer uses the adapter class MediaAdapter to transfer the required audio type without knowing the actual class that can play the audio in the required format
- AdapterPatternDemo uses the AudioPlayer class to play various formats
Code implementation:
1. Create interfaces for media players and more advanced media players
public interface MediaPlayer { public void play(String audioType, String fileName); } public interface AdvancedMediaPlayer { public void playVlc(String fileName); public void playMp4(String fileName); }
2. Create an entity class that implements the AdvancedMediaPlayer 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 } } 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); } }
3. Create an adapter class that implements the MediaPlayer 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); } } }
4. Create an entity class that implements the MediaPlayer interface
public class AudioPlayer implements MediaPlayer { MediaAdapter mediaAdapter; @Override public void play(String audioType, String fileName) { //Built in support for playing mp3 music files if(audioType.equalsIgnoreCase("mp3")){ System.out.println("Playing mp3 file. Name: "+ fileName); } //mediaAdapter provides support for playing other file formats else if(audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")){ mediaAdapter = new MediaAdapter(audioType); mediaAdapter.play(audioType, fileName); } else{ System.out.println("Invalid media. "+ audioType + " format not supported"); } } }
5. Use AudioPlayer to play different types of audio formats
public class AdapterPatternDemo { public static void main(String[] args) { AudioPlayer audioPlayer = new AudioPlayer(); audioPlayer.play("mp3", "beyond the horizon.mp3"); audioPlayer.play("mp4", "alone.mp4"); audioPlayer.play("vlc", "far far away.vlc"); audioPlayer.play("avi", "mind me.avi"); } }
The adapter pattern converts the interface of a class into another interface representation expected by the client. The purpose is to eliminate the compatibility of classes caused by interface mismatch. It is mainly divided into three categories: Adapter mode of class, adapter mode of object and adapter mode of interface. The adapter pattern defines a wrapper class that wraps objects with incompatible interfaces
Adapter mode of class:
public static class Source { public void method1() { System.out.println("this is original method!"); } } public interface Targetable { // The method is the same as that in the original class public void method1(); // Methods of new classes public void method2(); } public static class Adapter extends Source implements Targetable { @Override public void method2() { System.out.println("this is Targetable method!"); } } public static void main(String[] args) { Targetable targetable = new Adapter(); targetable.method1(); targetable.method2(); }
Adapter mode for object:
public static class Source { public void method1() { System.out.println("this is original method!"); } } public interface Targetable { // The method is the same as that in the original class public void method1(); // Methods of new classes public void method2(); } public static class Wrapper implements Targetable { private Source source; public Wrapper(Source source) { super(); this.source = source; } @Override public void method1() { source.method1(); } @Override public void method2() { System.out.println("this is Targetable method!"); } } public static void main(String[] args) { Source source = new Source(); Targetable targetable = new Wrapper(source); targetable.method1(); targetable.method2(); }
Adapter mode of interface:
The adapter mode of the interface is as follows: Sometimes there are multiple abstract methods in an interface we write. When we write the implementation class of the interface, we must implement all the methods of the interface, which is obviously wasteful, because not all the methods are needed, and sometimes only some are needed. Here, in order to solve this problem, we introduce the adapter mode of the interface with the help of an abstract class, The abstract class implements the interface, but we don't deal with the original interface and only contact the abstract class, so we write a class, inherit the abstract class and rewrite the methods we need.
3. Decorator mode
Introduction:
-
Decorator Pattern allows you to add new functionality to an existing object without changing its structure.
-
The decorator pattern creates a decorating class to wrap the original class, and provides additional functions on the premise of maintaining the integrity of the class method signature
-
give an example:
- After Mary's birthday, it's Sarly's turn. Don't ask her to choose by herself, otherwise the food expenses will be finished this month. Take out the picture I took on the top of Huashan last year, write "the best gift is Fita who loves you" on the back, and then buy a picture frame in the gift shop on the street (MM who sells gifts is also very beautiful), Find Mike, who is engaged in art design next door, and design a beautiful box to put it in... We are all decorators. We are all decorating me in the end. How do you understand?
-
Decoration mode:
- Decoration mode extends the function of objects in a transparent way to the client. It is an alternative to inheritance and provides more flexibility than inheritance.
- Dynamically add functions to an object, which can be dynamically undone.
- Add a very large number of functions produced by the arrangement and combination of some basic functions.
-
Intent:
Dynamically add some additional responsibilities to an object. In terms of adding functions, decorator pattern is more flexible than generating subclasses
-
Main solutions:
In general, in order to extend a class, we often use inheritance to implement it. Because inheritance introduces static features into the class, and with the increase of extension functions, subclasses will expand
Applicable scenarios:
- Monkey King has 72 changes. When he becomes a "Temple", he is still a monkey, but he has the function of a temple
- Whether a picture has a frame or not, it can be hung on the wall, but it usually has a frame, and in fact, the frame is hung on the wall. Before hanging on the wall, the painting can be covered with glass and framed; At this time, the painting, glass and frame form an object
- A function of an extension class
- Dynamic add function, dynamic undo
Structure:
- Create a Shape interface and an entity class that implements the Shape interface
- Create an abstract decoration class ShapeDecorator that implements the Shape interface, and take the Shape object as its instance variable
- The class RedShapeDecorator is created to implement the ShapeDecorator entity class
- Create a class DecoratorPatternDemo and use RedShapeDecorator to decorate Shape objects
Code implementation:
1. Create an interface and implement it
public interface Shape { void draw(); } public class Rectangle implements Shape { @Override public void draw() { System.out.println("Shape: Rectangle"); } } public class Circle implements Shape { @Override public void draw() { System.out.println("Shape: Circle"); } }
2. Create an abstract decoration class that implements the Shape interface
public abstract class ShapeDecorator implements Shape { protected Shape decoratedShape; public ShapeDecorator(Shape decoratedShape){ this.decoratedShape = decoratedShape; } public void draw(){ decoratedShape.draw(); } }
3. Create an entity decorator class that extends the ShapeDecorator 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"); } }
4. Use RedShapeDecorator to decorate Shape objects
public class DecoratorPatternDemo { public static void main(String[] args) { Shape circle = new Circle(); Shape redCircle = new RedShapeDecorator(new Circle()); Shape 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(); } }
Decorator mode Decorator,It is to add some new functions to an object, and it is dynamic, It is required that the decorated object and the decorated object implement the same interface, and the decorated object holds the instance of the decorated object.
public interface Sourceable { public void method(); } public static class Source implements Sourceable { @Override public void method() { System.out.println("the original method!"); } } public static class Decorator implements Sourceable { private Sourceable source; public Decorator(Sourceable source) { super(); this.source = source; } @Override public void method() { System.out.println("before decorator!"); source.method(); System.out.println("after decorator!"); } } public static void main(String[] args) { Sourceable source = new Source(); Sourceable obj = new Decorator(source); obj.method(); }
4. Appearance mode
Introduction:
- Facade Pattern hides the complexity of the system and provides an interface for the client to access the system
- The facade pattern involves a single class that provides simplified methods for client requests and delegate calls to existing system class methods
- Introduction:
- I have a professional Nikon camera. I like to manually adjust the aperture and shutter. In this way, the photos taken are professional, but MM doesn't understand these and can't teach for a long time. Fortunately, the camera has a Facade design mode. Adjust the camera to automatic. Just aim at the target and press the shutter. Everything is automatically adjusted by the camera, so MM can take a picture of me with this camera.
- Appearance mode:
- External communication with a subsystem must be carried out through a unified facade object.
- Appearance mode provides a high-level interface, which makes the subsystem easier to use.
- Each subsystem has only one facade class, and this facade class has only one instance, that is, it is a singleton mode. But the whole system can have multiple facade classes.
Applicable scenarios:
- To see a doctor in the hospital, you may have to go to registration, outpatient service, price setting and medicine taking, which makes the patient or his family feel very complicated. If there is a receptionist, it is very convenient to only let the receptionist handle it
- Three tier development mode of JAVA
- A module that provides external access to a complex module or subsystem
- The subsystems are relatively independent
- Prevent risks caused by low-level personnel
Structure:
- Create a Shape interface and an entity class that implements the Shape interface
- Define an appearance class ShapeMaker
- Defining classes ShapeMaker uses entity classes to represent user calls to these classes
- The definition class FacadePatternDemo uses the ShapeMaker class to display the results
Code implementation:
1. Create an interface and implement it
public interface Shape { void draw(); } public class Rectangle implements Shape { @Override public void draw() { System.out.println("Rectangle::draw()"); } } public class Square implements Shape { @Override public void draw() { System.out.println("Square::draw()"); } } public class Circle implements Shape { @Override public void draw() { System.out.println("Circle::draw()"); } }
2. Create an appearance class
public class ShapeMaker { private Shape circle; private Shape rectangle; private Shape square; public ShapeMaker() { circle = new Circle(); rectangle = new Rectangle(); square = new Square(); } public void drawCircle(){ circle.draw(); } public void drawRectangle(){ rectangle.draw(); } public void drawSquare(){ square.draw(); } }
3. Use this appearance class to draw various types of shapes
public class FacadePatternDemo { public static void main(String[] args) { ShapeMaker shapeMaker = new ShapeMaker(); shapeMaker.drawCircle(); shapeMaker.drawRectangle(); shapeMaker.drawSquare(); } }
5. Bridging mode
Introduction:
-
Bridge Pattern is used to decouple abstraction from realization, so that they can change independently
-
The bridging mode involves an interface as a bridge, which makes the function of the entity class independent of the interface implementation class. The two types of classes can be structurally changed without affecting each other
-
That is to say, changing the strong relationship between them into a weak relationship, that is, using the combination / aggregation relationship instead of the inheritance relationship between the abstraction and implementation of a software system, so that the two can change independently.
-
give an example:
- If you meet mm in the morning, you should say good morning. If you meet mm in the evening, you should say good evening; When you meet mm wearing a new dress, you should say that your clothes are so beautiful. When you meet MM's new hairstyle, you should say that your hair is so beautiful. Don't ask me the question "how to say when I met mm with a new hairstyle in the morning". Just combine it with BRIDGE
-
Intent:
Separate the abstract part from the implementation part so that they can change independently
-
Main solutions:
When there are many possible changes, using inheritance will cause class explosion and inflexible expansion
-
When to use:
The implementation system may have multiple angle classifications, and each angle may change
-
How to solve:
Separate this multi angle classification, let them change independently and reduce the coupling between them
Applicable scenarios:
-
Zhu Bajie was reincarnated from Marshal Tianpeng to pig. The mechanism of reincarnation divides the earth into two levels: soul and body. The former is equivalent to abstraction and the latter is equivalent to realization
Through the delegation of functions, creatures call the functions of physical objects, so that creatures can choose dynamically
-
The switch on the wall, you can see that the switch is abstract, regardless of how to realize it
Structure:
- Create a DrawAPI interface as a bridge implementation and entity classes RedCircle and GreenCircle that implement the DrawAPI interface
- Shape is an abstract class that uses the objects of the DrawAPI
- BridgePatternDemo uses the Shape class to draw circles of different colors
Code implementation:
1. Create bridge implementation interfaces and implementation classes
public interface DrawAPI { public void drawCircle(int radius, int x, int y); } public class RedCircle implements DrawAPI { @Override public void drawCircle(int radius, int x, int y) { System.out.println("Drawing Circle[ color: red, radius: " + radius +", x: " +x+", "+ y +"]"); } } public class GreenCircle implements DrawAPI { @Override public void drawCircle(int radius, int x, int y) { System.out.println("Drawing Circle[ color: green, radius: " + radius +", x: " +x+", "+ y +"]"); } }
2. Create an abstract class Shape using the DrawAPI interface
public abstract class Shape { protected DrawAPI drawAPI; protected Shape(DrawAPI drawAPI){ this.drawAPI = drawAPI; } public abstract void draw(); } public class Circle extends Shape { private int x, y, radius; public Circle(int x, int y, int radius, DrawAPI drawAPI) { super(drawAPI); this.x = x; this.y = y; this.radius = radius; } public void draw() { drawAPI.drawCircle(radius,x,y); } }
3. Use Shape and DrawAPI classes to draw circles of different colors
public class BridgePatternDemo { public static void main(String[] args) { Shape redCircle = new Circle(100,100, 10, new RedCircle()); Shape greenCircle = new Circle(100,100, 10, new GreenCircle()); redCircle.draw(); greenCircle.draw(); } }
6. Combination mode
Introduction:
-
Composite Pattern, also known as partial overall pattern, is used to treat a group of similar objects as a single object
-
The composite pattern creates a class containing its own group of objects, which provides a way to modify the same group of objects.
-
give an example:
- Mary has her birthday today.
- "You want to give me a present for my birthday."
- "Well, well, go to the store and choose for yourself."
- "This T-shirt is very beautiful. Buy it. This skirt looks good. Buy it. This bag is also good. Buy it."
- "Hey, I bought three. I only promised to give one gift."
- "What? A T-shirt, a skirt and a bag just match. Miss, please wrap it up."
- "......",
- MM can use Composite mode. Can you?
-
Composite mode:
- The composition pattern organizes objects into a tree structure, which can be used to describe the relationship between whole and part.
- Composite pattern is a pattern that deals with the tree structure of objects.
- The composition pattern expresses the relationship between part and whole in a tree structure.
- The composition mode enables the client to treat individual component objects equally with the composite objects composed of them.
-
When to use:
- Part of the object you want to represent - the overall hierarchy (tree structure)
- Users are expected to ignore the difference between composite objects and single objects, and users will use all objects in the composite structure uniformly
-
How to solve:
The branch and leaf realize a unified interface, and the interface is combined inside the branch
-
Key codes:
The interface is combined inside the tree branch, and contains the internal attribute List, in which Component is placed
Applicable scenarios:
- An arithmetic expression includes an operand, an operator, and another operand. The other operator can also be an operand tree, an operator, and another operand
- In JAVA AWT and SWING, the Button and Checkbox are leaves and the Container is branches
- Partial and overall scenes, such as tree menu, file and folder management
Structure:
- Class Employee, which is treated as a composite model class
- The CompositePatternDemo class uses the Employee class to add a department hierarchy and print all employees
Code implementation:
1. Create an Employee class with a list of Employee objects
public class Employee { private String name; private String dept; private int salary; private List<Employee> subordinates; //Constructor public Employee(String name,String dept, int sal) { this.name = name; this.dept = dept; this.salary = sal; subordinates = new ArrayList<Employee>(); } public void add(Employee e) { subordinates.add(e); } public void remove(Employee e) { subordinates.remove(e); } public List<Employee> getSubordinates(){ return subordinates; } public String toString(){ return ("Employee :[ Name : "+ name +", dept : "+ dept + ", salary :" + salary+" ]"); } }
2. Use the Employee class to create and print a hierarchy of employees
public class CompositePatternDemo { public static void main(String[] args) { Employee CEO = new Employee("John","CEO", 30000); Employee headSales = new Employee("Robert","Head Sales", 20000); Employee headMarketing = new Employee("Michel","Head Marketing", 20000); Employee clerk1 = new Employee("Laura","Marketing", 10000); Employee clerk2 = new Employee("Bob","Marketing", 10000); Employee salesExecutive1 = new Employee("Richard","Sales", 10000); Employee salesExecutive2 = new Employee("Rob","Sales", 10000); CEO.add(headSales); CEO.add(headMarketing); headSales.add(salesExecutive1); headSales.add(salesExecutive2); headMarketing.add(clerk1); headMarketing.add(clerk2); //Print all employees of the organization System.out.println(CEO); for (Employee headEmployee : CEO.getSubordinates()) { System.out.println(headEmployee); for (Employee employee : headEmployee.getSubordinates()) { System.out.println(employee); } } } }
7. Sharing mode
Introduction:
-
Flyweight Pattern is mainly used to reduce the number of objects created to reduce memory consumption and improve performance
-
The meta pattern attempts to reuse existing homogeneous objects, and if no matching object is found, a new object is created
-
give an example:
- I'm tired of texting with mm every day. I recently bought a new mobile phone. I can store some commonly used sentences in the mobile phone. When I want to use them, I can take them out directly and add MM's name in front of them to send them. I don't have to type one word at a time. The shared sentence is Flyweight, and the name of MM is the extracted external feature, which is used according to the context.
-
Enjoy yuan mode: FLYWEIGHT refers to the lightest weight in boxing competition.
- The shared meta model efficiently supports a large number of fine-grained objects in a shared way.
- The key of sharing meta model is to distinguish intrinsic state and extrinsic state.
- The intrinsic state is stored inside the element and will not change with the change of the environment.
- The intrinsic state changes with the change of environment.
- The intrinsic state cannot affect the intrinsic state. They are independent of each other.
- Distinguish the shareable state from the unsharable state from the regular class, and eliminate the unsharable state from the class.
- Instead of directly creating shared objects, the client should use a factory object to create shared objects.
- Meta sharing mode greatly reduces the number of objects in memory.
-
Intent:
Use sharing technology to effectively support a large number of fine-grained objects
-
Main solutions:
When there are a large number of objects, it may cause memory overflow. We abstract the common parts. If there are the same business requests, we can directly return the existing objects in memory to avoid re creation
-
When to use:
- There are a large number of objects in the system
- These objects consume a lot of memory
- Most of the states of these objects can be externalized
- These objects can be divided into many groups according to the intrinsic state. When the intrinsic objects are removed from the objects, each group of objects can be replaced by an object
- The system does not depend on the identity of these objects, which are indistinguishable
Applicable scenarios:
- String in JAVA, if any, will be returned. If not, a string will be created and saved in the string cache pool
- Data pool of database
- The system has a large number of similar objects
- Scenarios requiring buffer pools
Structure:
-
Define a Shape interface and an entity class Circle that implements the Shape interface
-
Define factory class ShapeFactory
ShapeFactory has a Circle HashMap, where the key name is the color of the Circle object
Whenever a request is received, a circle of a specific color is created
ShapeFactory checks the circle object in its HashMap. If it finds the circle object, it returns it. Otherwise, it will create a new object stored in HashMap for subsequent use and return it to the client
-
The definition class FlyWeightPatternDemo uses ShapeFactory to obtain Shape objects
It will pass information (red / green / blue/ black / white) to ShapeFactory to get the color of the object it needs
Code implementation:
1. Define an interface and implementation class
public interface Shape { void draw(); } public class Circle implements Shape { private String color; private int x; private int y; private int radius; public Circle(String color){ this.color = color; } public void setX(int x) { this.x = x; } public void setY(int y) { this.y = y; } public void setRadius(int radius) { this.radius = radius; } @Override public void draw() { System.out.println("Circle: Draw() [Color : " + color +", x : " + x +", y :" + y +", radius :" + radius); } }
2. Create a factory to generate objects of entity classes based on the given information
public class ShapeFactory { private static final HashMap<String, Shape> circleMap = new HashMap(); public static Shape getCircle(String color) { Circle circle = (Circle)circleMap.get(color); if(circle == null) { circle = new Circle(color); circleMap.put(color, circle); System.out.println("Creating circle of color : " + color); } return circle; } }
3. Using the factory, the object of entity class is obtained by passing color information
public class FlyweightPatternDemo { private static final String colors[] = { "Red", "Green", "Blue", "White", "Black" }; public static void main(String[] args) { for(int i=0; i < 20; ++i) { Circle circle = (Circle)ShapeFactory.getCircle(getRandomColor()); circle.setX(getRandomX()); circle.setY(getRandomY()); circle.setRadius(100); circle.draw(); } } private static String getRandomColor() { return colors[(int)(Math.random()*colors.length)]; } private static int getRandomX() { return (int)(Math.random()*100 ); } private static int getRandomY() { return (int)(Math.random()*100); } }