工厂方法模式在 Java API 中的应用比比皆是:java.util.Collection 接口的 iterator 方法就是一个非常著名的工厂方法模式的演示样例;java.net.URLStreamHandlerFactory 的 createURLStreamHandler(String protocol) 也是工厂方法模式的一个非常经典的应用,URLStreamHandlerFactory 定义了一个用来创建 URLStreamHandler 实例的 createURLStreamHandler 方法,详细怎么创建?详细实现类说了算;此外。Java API 中工厂方法模式应用样例还有 java.net.ContentHandlerFactory、java.net.URL 的 openConnection 方法……。
Gof 把工厂方法模式归类到对象创建型模式,《设计模式:可复用面向对象软件的基础》对工厂方法模式做出了明白的定义:"Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses." 翻译过来就是:"为创建一个对象定义一个接口,但把详细创建哪个类的实例留给子类决定。工厂方法同意将一个类的初始化延迟到自己的子类。"
Why 工厂方法模式?
通过使用工厂方法创建对象。我们能够避免client代码依赖于它所使用的接口的详细实现。client不再须要把对象创建的构造方法注入到自己的代码中去。client仅仅须要调用工厂,由工厂来决定符合要求的子类的创建过程。此外,工厂方法还能够满足每次构造不同对象、对象的构造非常复杂、对象的构造依赖详细环境等等需求。
工厂方法模式的使用场合
换句话讲,假设有新产品加入,简单工厂须要改动自己的工厂类。而工厂方法仅仅需添加新工厂子类 - 简单工厂对 OCP 原则的支持力度不如工厂方法。
为了提高程序性能,我们要用 Java 进行 JNI 调用底层的加解密方法。
《Java Web 应用调用 C++ 加解密方法》分析
既然牵涉底层调用。就应该考虑到程序跨平台的问题。另外,应用至少要能支持 Linux 和 Windows。以后还可能会部署在 mac。并且这些平台还分为 64 位和 32 位。因此我们要为每一个平台都要准备一个加解密底层库,由于底层库位数不同并不兼容,所以每一个平台下又要有两个库:32 位一个,64 位一个。
每一个库都应该有对应的类进行载入,比方本文工厂方法模式演示样例中的详细产品类之中的一个的 com.defonds.cloud.tool.config.encrypt.EncryptorLinuxAmd64.java。也就是我们的加解密类,这个类写完并编译好之后,使用 shell 生成 com_defonds_cloud_tool_config_encrypt_EncryptorLinuxAmd64.h 头文件,C/C++ 程序猿依据每一个平台的头文件封装加解密库。
加解密类的实例化。我们就用工厂方法模式管理起来。
《Java Web 应用调用 C++ 加解密方法》类设计
《Java Web 应用调用 C++ 加解密方法》源代码
client类 EncryptorUtil 源代码:
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 linux
encryptorFactory = new EncryptorFactoryLinux();
} else if (osName.contains("Windows")) { // os is windows
encryptorFactory = new EncryptorFactoryWindows();
} else { // os is mac
encryptorFactory = 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);
}
}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);
}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
}
}
@Override
public String encrypt(String content, boolean flag) {
// TODO Auto-generated method stub
return this.encryptStr(content, flag);
}
}package com.defonds.cloud.tool.config.encrypt.factory;
import com.defonds.cloud.tool.config.encrypt.Encryptor;
public interface EncryptorFactory {
public Encryptor getEncryptor();
}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");
@Override
public Encryptor getEncryptor() {
if (osArch.equals("amd64")) { // os is linux amd64
return new EncryptorLinuxAmd64();
} else { // os is linux i386
return new EncryptorLinuxI386();
}
}
} 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);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 windows
if (osArch.equals("amd64")) { // os is windows amd64
return new EncryptorWindowsAmd64();
} else { // os is windows x86
return new EncryptorWindowsX86();
}
} else { // os is linux
if (osArch.equals("amd64")) { // os is linux amd64
return new EncryptorLinuxAmd64();
} else { // os is linux i386
return new EncryptorLinuxI386();
}
}
}
}
后记 2
执行 jni 时,假设遇到相似于 java.lang.UnsatisfiedLinkError: /tmp/libaesjni_linux6345613888084265218.so: /tmp/libaesjni_linux6345613888084265218.so: wrong ELF class: ELFCLASS32 (Possible cause: architecture word width mismatch) 的错误:
Exception in thread "main" java.lang.UnsatisfiedLinkError: /tmp/libaesjni_linux6345613888084265218.so: /tmp/libaesjni_linux6345613888084265218.so: 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)
解决的方法:分别提供 64 位和 32 位库。
后记 3
假设 jni 时遇到下面错误:
java: symbol lookup error: /tmp/libaesjni4570314921835538044.so: undefined symbol: aesrun
java: symbol lookup error: /tmp/libaesjni8667398299924347273.so: undefined symbol: GetStringUTFChars
解决的方法:这是 C++ 调用了 C 的函数,编译规则不一样造成,把 C++ 代码 (cpp 后缀) 所有换成 C 代码,又一次编译就好了。
參考资料
原文:http://www.cnblogs.com/cxchanpin/p/7236694.html