5 practical application of design patterns: Factory method patterns, 5 of design patterns
Definition of factory method mode
The factory method model is widely used. The factory method mode is widely used in Java APIs: java. util. the iterator method of the Collection interface is an example of a well-known factory method pattern; java.net. createURLStreamHandler (String protocol) of URLStreamHandlerFactory is also a classic application of the factory method mode. URLStreamHandlerFactory defines a createURLStreamHandler method used to create URLStreamHandler instances. How to create it? The specific implementation class has the final say; in addition, the factory method mode application examples in Java API include java.net. ContentHandlerFactory and java.net. URL openConnection method .......
Gof classifies the factory method pattern into the object creation pattern, and defines the factory method pattern clearly in design pattern: Basis for reusable object-oriented software: "Define an interface for creating an object, but let subclasses decide which class to instantiate. factory Method lets a class defer instantiation to subclasses. "translation :"Defines an interface for creating an object, but leaves the instance of the specific class to the subclass. The factory method allows the initialization of a class to be delayed to its own subclass."
Why factory method mode?
By using the factory method to create an object, we can avoid the client code relying on the specific implementation of the interface it uses. The client no longer needs to inject the constructor of object creation into its own code. The client only needs to call the factory to determine the creation process of child classes that meet the requirements. In addition, the factory method can meet the needs of constructing different objects each time, complex object structures, and Object Structures dependent on specific environments.
Use Cases of factory method mode
- The client does not know which subclass it is to create.
- A class wants its own subclass to define the creation process of an object.
- Class will create a responsibility proxy for an object to one of the help subclass, and you want to localize which subclass as the proxy information.
Factory method mode VS simple factory Mode
- Simple factory, also known as "static factory", is the biggest difference between the factory method and the simple factory, which is also the feature of the two modes that are most likely to be separated.
- Although both of them are partial encapsulation of object creation, a simple factory focuses on code reuse of object creation, reuse of created instances, or uniformity of instance creation; the factory method focuses on the implementation of the specific creation logic of child classes.
- In the simple factory mode, the factory class is the core of product class instantiation, and the factory method mode hands over the initialization work to the subclass implementation. In other words, if a new product is added, the simple factory needs to modify its own factory class, while the factory method only needs to add a new factory subclass-the simple factory does not support the OCP principle as well as the factory method.
Java Web application calls C ++ encryption and decryption Methods
As we all know, Java's file encryption and decryption efficiency is not as good as the underlying C/C ++. To improve program performance, we need to use Java for JNI to call the underlying encryption and decryption methods.
Analysis of Java Web application Calling C ++ encryption and decryption Methods
Since underlying calls are involved, cross-platform applications should be considered. In addition, applications must support at least Linux and Windows, and may be deployed on mac in the future. These platforms are also divided into 64-bit and 32-bit. Therefore, we need to prepare an underlying encryption/Decryption library for each platform. because the number of digits of the underlying database is not compatible, there must be two databases under each platform: 32-bit and 64-bit.
Each database should have corresponding classes for loading, such as com. defonds. cloud. tool. config. encrypt. encryptorLinuxAmd64.java, which is our encryption and decryption class. After this class is written and compiled, the ghost header file is generated using shell. C/C ++ programmers encapsulate the encryption and decryption libraries based on the header files of each platform.
The encryption/Decryption class is instantiated and managed in the factory mode.
Java Web application Calling C ++ encryption and decryption method design
Java Web application Calling C ++ encryption and decryption method source code
Client class EncryptorUtil source code:
package com.defonds.cloud.tool.config.util;import com.defonds.cloud.tool.config.encrypt.Encryptor;import com.defonds.cloud.tool.config.encrypt.factory.EncryptorFactory;import com.defonds.cloud.tool.config.encrypt.factory.EncryptorFactoryLinux;import com.defonds.cloud.tool.config.encrypt.factory.EncryptorFactoryMac;import com.defonds.cloud.tool.config.encrypt.factory.EncryptorFactoryWindows;public class EncryptorUtil {private static String osName = System.getProperties().getProperty("os.name");private static Encryptor encryptor;static {EncryptorFactory encryptorFactory;if (osName.equals("Linux")) { // os is linuxencryptorFactory = new EncryptorFactoryLinux();} else if (osName.contains("Windows")) { // os is windowsencryptorFactory = new EncryptorFactoryWindows();} else { // os is macencryptorFactory = new EncryptorFactoryMac();}encryptor = encryptorFactory.getEncryptor();}/** * * @param content - the string to be encrypt or decrypt * @param flag - encrypt flag, true is encrypt, false is decrypt * @return - string after encrypt or decrypt */public static String encryptorStr(String content, boolean flag) {return EncryptorUtil.encryptor.encrypt(content, flag);}}
Product Encryptor interface:
package com.defonds.cloud.tool.config.encrypt;public interface Encryptor {/** * @param content str to be encrypted * @param flag true:encrypt false:decrypt * @return */public String encrypt(String content, boolean flag);}
One of the specific product categories is EncryptorLinuxAmd64 source code (according to the libaesjni written by EncryptorLinuxAmd64. the so library is already in the/com/defonds/cloud/tool/config/encrypt/native/linux/amd64 directory under classpath ):
package com.defonds.cloud.tool.config.encrypt;import java.io.IOException;import com.defonds.cloud.tool.config.util.NativeUtils;public class EncryptorLinuxAmd64 implements Encryptor {// Native method declaration // use the keyword "native" indicate this is an 'unsafe' mtehod for java native String encryptStr(String content, boolean flag); // Load the library static { try { System.loadLibrary("libaesjni"); }catch (UnsatisfiedLinkError e) { try {NativeUtils.loadLibraryFromJar("/com/defonds/cloud/tool/config/encrypt/native/linux/amd64/libaesjni.so");} catch (IOException e1) {throw new RuntimeException(e1);} // during runtime. .DLL within .JAR } }@Overridepublic String encrypt(String content, boolean flag) {// TODO Auto-generated method stubreturn this.encryptStr(content, flag);}}
Factory interface EncryptorFactory:
package com.defonds.cloud.tool.config.encrypt.factory;import com.defonds.cloud.tool.config.encrypt.Encryptor;public interface EncryptorFactory {public Encryptor getEncryptor();}
One of the specific factory classes is EncryptorFactoryLinux source code:
package com.defonds.cloud.tool.config.encrypt.factory;import com.defonds.cloud.tool.config.encrypt.Encryptor;import com.defonds.cloud.tool.config.encrypt.EncryptorLinuxAmd64;import com.defonds.cloud.tool.config.encrypt.EncryptorLinuxI386;public class EncryptorFactoryLinux implements EncryptorFactory {private static String osArch = System.getProperties().getProperty("os.arch");@Overridepublic Encryptor getEncryptor() {if (osArch.equals("amd64")) { // os is linux amd64return new EncryptorLinuxAmd64();} else { // os is linux i386return new EncryptorLinuxI386();}}}
Java Web application calls the C ++ encryption and decryption method to test
The test code is as follows:
String abc = "abc";System.out.println("before encrypt:" + abc);String abcEncrypted = EncryptorUtil.encryptorStr(abc, true);System.out.println("after encrypt:" + abcEncrypted);String abc2 = EncryptorUtil.encryptorStr(abcEncrypted, false);System.out.println("after decrypt:" + abc2);
Running result:
Before encrypt: abc
After encrypt: 3a5dd7db74fdab404e980805b1998e81
After decrypt: abc
Postscript 1
Readers may find that Java Web application calls the C ++ encryption and decryption method can be fully implemented in a simple factory mode, and even the effect may be better (because you don't need to add new factory objects every time):
public class EncryptorFactory {private static Properties sp = System.getProperties(); private static String osName = sp.getProperty("os.name");private static String osArch = sp.getProperty("os.arch");private static int index2 = osName.indexOf("indows");private static boolean isWindows = false;static {if (index2 != -1) {isWindows = true;} }public static Encryptor getEncryptor() {if (isWindows) { // os is windowsif (osArch.equals("amd64")) { // os is windows amd64return new EncryptorWindowsAmd64();} else { // os is windows x86return new EncryptorWindowsX86();}} else { // os is linuxif (osArch.equals("amd64")) { // os is linux amd64return new EncryptorLinuxAmd64();} else { // os is linux i386return new EncryptorLinuxI386();}}}}
Originally, a simple factory is a special case of a factory method. GOF did not even describe it in 23 design models, and many documents do not have the concept of a simple factory. So when will simple factories be used? I suggest,
If you can predict the situation of all products, use a simple factory. Otherwise, use the factory method..
Postscript 2
When running jni, if an error similar to java. lang. UnsatisfiedLinkError:/tmp/character: wrong ELF class: ELFCLASS32 (Possible cause: architecture word width mismatch) occurs:
Exception in thread "main" java. lang. UnsatisfiedLinkError:/tmp/keys: wrong ELF class: ELFCLASS32 (Possible cause: architecture word width mismatch)
At java. lang. ClassLoader $ NativeLibrary. load (Native Method)
At java. lang. ClassLoader. loadLibrary0 (ClassLoader. java: 1747)
At java. lang. ClassLoader. loadLibrary (ClassLoader. java: 1643)
At java. lang. Runtime. load0 (Runtime. java: 787)
At java. lang. System. load (System. java: 1022)
At com. defonds. cloud. tool. config. util. NativeUtils. loadLibraryFromJar (NativeUtils. java: 91)
At com. defonds. cloud. tool. config. encrypt. EncryptorLinux. <clinit> (EncryptorLinux. java: 20)
At com. defonds. cloud. tool. config. util. EncryptorFactory. getEncryptor (EncryptorFactory. java: 24)
At com. defonds. cloud. tool. config. ConfigUtil. <clinit> (ConfigUtil. java: 7)
At TestTime. main (TestTime. java: 26)
Solution: Provide 64-bit and 32-bit libraries respectively.
Postscript 3
If jni encounters the following error:
Java: symbol lookup error:/tmp/libaesjni4570314921835538044.so: undefined symbol: aesrun
Java: symbol lookup error:/tmp/libaesjni8667398299924425273.so: undefined symbol: GetStringUTFChars
Solution: this is because C ++ calls C functions and the compilation rules are different. replace all C ++ code (cpp suffix) with C code and recompile it.
References
- C ++ and Java Mixed Programming
[Reward] understanding the design model-the factory model and the factory Method
Factory mode definition: Provides interfaces for object creation.
Why?
The factory mode is our most commonly used model. The famous Jive forum has used the factory mode extensively. The factory mode can be seen everywhere in Java program systems.
Why is the factory model so commonly used? Because the factory mode is equivalent to creating the new instance object, we often need to generate instance objects according to Class, for example, A a = new A () Factory mode is also used to create instance objects, so in the future, there will be multiple eyes. Can you consider using the factory model? Although doing so may do more work, it will bring more scalability and as few modifications as possible to your system.
Let's take the Sample class as an example. If we want to create an instance object for the Sample:
Sample sample = new Sample ();
However, we usually perform vertex initialization when creating a sample instance, such as assigning values to query databases.
First, we can use the Sample constructor to generate an instance and write it as follows:
Sample sample = new Sample (parameter );
However, if Initialization is not as simple as assigning values when creating a sample instance, it may be a long piece of code. If it is also written to the constructor, then your code is ugly (Refactor reorganization is required ).
The reason is that the Code is ugly. Beginners may not feel this way. We will analyze the following. If the initialization work is a long piece of code, it means a lot of work to be done and a lot of work is loaded into a method, it is very dangerous to put a lot of eggs in one basket. This is also based on Java's object-oriented principle. The object-oriented Encapsulation (Encapsulation) and dispatch (Delegation) tell us that, assign long codes as much as possible to "cut" each segment, and then "encapsulate" each segment (reducing the coupling and association between segments). In this way, risks are dispersed, if you need to modify each segment in the future, nothing will happen again.
In this example, we need to separate the instance creation and use, that is, separate the large amount of initialization work required to create an instance from the constructor of the Sample.
In this case, we need the Factory mode to generate the object, and we cannot use the simple new Sample (parameter) above ). In addition, if the Sample has an inheritance such as MySample, We need to abstract the Sample into an interface according to the interface-oriented programming. sample is an interface with two subclasses: MySample and HisSample. we want to instantiate them as follows:
Sample mysample = new MySample ();
Sample hissample = new HisSample ();
As the project goes deeper, the Sample may "give birth to many sons", so we need to instantiate these sons one by one. Even worse, we may need to modify the previous Code: add an instance that later gave birth to a son. this is unavoidable in traditional programs.
But if you consciously use the factory model from the very beginning, these troubles will be gone.
Factory method
You will create a factory dedicated to producing Sample instances:
Public class Factory {
Public static Sample creator (int which ){
// GetClass generates samples. Generally, dynamic classes can be used to load the loaded classes.
If (which = 1)
Return new SampleA ();
Else if (which = 2)
Return new SampleB ();
}
}
In your program, if you want to instantiate the Sample, use
Sample sampleA = Factory. creator (1 );
In this way, the entire article will not be... the remaining full text>
What design patterns are familiar to you? Write the implementation code of Singleton Mode
There are 23 design modes in total!
Reference the "software secrets-the point of design patterns" book:
According to the purpose, the design patterns can be divided into creation patterns, structural patterns, and behavior patterns.
The creation mode is used to process the object creation process, the structure mode is used to process the combination of classes or objects, and the behavior mode is used to describe how classes or objects interact and how responsibilities are assigned.
The creation mode is used to process the object creation process. It mainly includes the following five design modes:
Factory Method Pattern)
Abstract Factory Pattern)
Builder Pattern)
Prototype Pattern)
Singleton Pattern)
The structural mode is used to process the combination of classes or objects. It mainly includes the following seven design modes:
Adapter Pattern)
Bridge Pattern)
Composite Pattern)
Decorator Pattern)
Facade Pattern)
Flyweight Pattern)
Proxy Pattern)
The behavior pattern is used to describe how classes or objects interact and how responsibilities are assigned. It mainly includes the following 11 design patterns:
Chain of Responsibility Pattern)
Command Pattern)
Interpreter mode (Interpreter Pattern)
Iterator Pattern)
Mediator Pattern)
Memory memorandum mode (Memento Pattern)
Observer Pattern)
State Pattern)
Strategy Pattern)
Template Method Pattern)
Visitor Pattern)
Singleton mode Implementation 1:
Public class Singleton {
// Class shared Instance Object
Private static Singleton singleton = null;
// Private constructor
Private Singleton (){
System. out. println ("-- this is Singleton !!! ");
}
// Obtain the singleton Method
Public synchronized static Singleton getInstance (){
// Determine whether the shared object is null. If it is null, a new object is created.
If (singleton = null ){
Singleton = new Singleton ();
}
Return singleton;
}
}
Singleton mode implementation 2:
Public class Singleton {
// Class shared Instance Object Instantiation
Private s... the remaining full text>