优雅案例一
问题思考:在考虑设计工具类时候,大多数情况我都习惯的都是涉及为一个类,然后定义一个静态方法,然后通过调用这个静态方法复用,大体如下
举例说明:类型转换工具类,bean与map的转换,说明两种场景
- bean2Map是bean转换map的一种实现,我们大多数都是这样设计的工具类
- map2Bean与map2Bean2是map转向bean的两种不同实现,功能一致
public class PropertyUtils {
public static Map<String, Object> bean2Map(Object object)
throws IntrospectionException, IllegalAccessException, InstantiationException, InvocationTargetException {
BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass());
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
Map<String, Object> map = new HashMap<>();
for (PropertyDescriptor pd : propertyDescriptors) {
if (pd.getPropertyType().isAssignableFrom(Class.class)) {
continue;
}
String propertyName = pd.getName();
Method readMethod = pd.getReadMethod();
if (!readMethod.isAccessible()) {
readMethod.setAccessible(true);
}
Object propertyValue = readMethod.invoke(object);
map.put(propertyName, propertyValue);
}
return map;
}
public static <T> T map2Bean(Class<T> type, Map<String, Object> map)
throws IntrospectionException, IllegalAccessException, InstantiationException, InvocationTargetException {
BeanInfo beanInfo = Introspector.getBeanInfo(type);
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
T obj = type.newInstance();
for (PropertyDescriptor pd : propertyDescriptors) {
if (pd.getPropertyType().isAssignableFrom(Class.class)) {
continue;
}
String propertyName = pd.getName();
if (map.containsKey(propertyName)) {
Object value = map.get(propertyName);
Method setter = pd.getWriteMethod();
if (!setter.isAccessible()) {
setter.setAccessible(true);
}
setter.invoke(obj, value);
}
}
return obj;
}
public static <T> T map2Bean2(Class<T> type, Map<String, Object> map)
throws IntrospectionException, IllegalAccessException, InstantiationException, InvocationTargetException {
T obj = type.newInstance();
for (Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
PropertyDescriptor pd = new PropertyDescriptor(key, type);
Method writeMethod = pd.getWriteMethod();
if (!writeMethod.isAccessible()) {
writeMethod.setAccessible(true);
}
writeMethod.invoke(obj, value);
}
return obj;
}
}
使用类封装一层逻辑
针对bean2Map的问题,由于是类型转换,我们很容易想到适配者思想
这里的适配者模式不是严格模式,只是借助思想
抽象出接口
/**
* Created by it
* Created in 2019年3月26日
* Description: 适配器思想
*/
public abstract class AbstracAdapter<T, D> {
protected T t;
public AbstracAdapter(T t) {
this.t = t;
}
public abstract D conver() throws Exception;
}
具体实现,这里可以留扩展,Bean2MapAdapter可以添加其他方法
/**
* Created by it
* Created in 2019年3月26日
* Description: 适配器思想
*/
public class Bean2MapAdapter extends AbstracAdapter<Object, Map<String, Object>> {
public Bean2MapAdapter(Object t) {
super(t);
}
public Map<String, Object> conver() throws IntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Map<String, Object> map = new HashMap<>();
BeanInfo beanInfo = Introspector.getBeanInfo(t.getClass());
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : propertyDescriptors) {
if (pd.getPropertyType().isAssignableFrom(Class.class)) {
continue;
}
String propertyName = pd.getName();
Method readMethod = pd.getReadMethod();
if (!readMethod.isAccessible()) {
readMethod.setAccessible(true);
}
Object propertyValue = readMethod.invoke(t);
map.put(propertyName, propertyValue);
}
return map;
}
}
优雅的封装工具类更改为
/**
*
* Created by it
* Created in 2019年3月25日
* Description: 提供bean转换
*/
public class PropertyUtils {
/**
* bean -> Map
*/
public static Map<String, Object> bean2Map(Object object) {
Bean2MapAdapter adapter = new Bean2MapAdapter(object);
try {
return adapter.conver();
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | IntrospectionException e) {
throw new RuntimeException(e);
}
}
}
策略者整合
针对map2Bean与map2Bean2的两种不同实现,我们很容易想到策略者模式,针对不同的实现封装类
抽象出接口
public interface AbstractMap2Bean {
<T> T map2Bean(Class<T> type, Map<String, Object> map) throws Exception;
}
具体实现,这里是两种,也可以扩展任意种
/**
* Created by it
* Created in 2019年3月26日
* Description: 适配器思想
*/
public class Bean2MapAdapter extends AbstracAdapter<Object, Map<String, Object>> {
public Bean2MapAdapter(Object t) {
super(t);
}
public Map<String, Object> conver() throws IntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Map<String, Object> map = new HashMap<>();
BeanInfo beanInfo = Introspector.getBeanInfo(t.getClass());
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor pd : propertyDescriptors) {
if (pd.getPropertyType().isAssignableFrom(Class.class)) {
continue;
}
String propertyName = pd.getName();
Method readMethod = pd.getReadMethod();
if (!readMethod.isAccessible()) {
readMethod.setAccessible(true);
}
Object propertyValue = readMethod.invoke(t);
map.put(propertyName, propertyValue);
}
return map;
}
}
优雅的封装工具类更改为
/**
*
* Created by it
* Created in 2019年3月25日
* Description: 提供bean转换
*/
public class PropertyUtils {
/**
* bean -> Map
*/
public static Map<String, Object> bean2Map(Object object) {
Bean2MapAdapter adapter = new Bean2MapAdapter(object);
try {
return adapter.conver();
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | IntrospectionException e) {
throw new RuntimeException(e);
}
}
}
将原工具类方法map2Bean封装如下两种
/**
* Created by it
* Created in 2019年3月26日
* Description: 用bean属性来做循环
*/
public class DefaultMap2Bean implements AbstractMap2Bean {
@Override
public <T> T map2Bean(Class<T> type, Map<String, Object> map) throws IntrospectionException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
BeanInfo beanInfo = Introspector.getBeanInfo(type);
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
T obj = type.newInstance();
for (PropertyDescriptor pd : propertyDescriptors) {
if (pd.getPropertyType().isAssignableFrom(Class.class)) {
continue;
}
String propertyName = pd.getName();
if (map.containsKey(propertyName)) {
Object value = map.get(propertyName);
Method setter = pd.getWriteMethod();
if (!setter.isAccessible()) {
setter.setAccessible(true);
}
setter.invoke(obj, value);
}
}
return obj;
}
}
第二种
/**
* Created by it
* Created in 2019年3月26日
* Description: 用map属性来做循环
*/
public class PriorityMap4Map2Bean implements AbstractMap2Bean {
@Override
public <T> T map2Bean(Class<T> type, Map<String, Object> map) throws IntrospectionException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
T obj = type.newInstance();
for (Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
PropertyDescriptor pd = new PropertyDescriptor(key, type);
Method writeMethod = pd.getWriteMethod();
if (!writeMethod.isAccessible()) {
writeMethod.setAccessible(true);
}
writeMethod.invoke(obj, value);
}
return obj;
}
}
修改工具类,这里把之前优雅很多,特别在spring中,利用spring的配置加载,可以加载不同的具体实现
/**
* Created by it
* Created in 2019年3月26日
* Description: 提供bean转换
*/
public class PropertyUtils {
/**
* Map -> bean
*/
public static <T> T map2Bean(Class<T> type, Map<String, Object> map) {
try {
AbstractMap2Bean delegate = new DefaultMap2Bean();
return delegate.map2Bean(type, map);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Map -> bean
*/
public static <T> T map2Bean2(Class<T> type, Map<String, Object> map) {
try {
AbstractMap2Bean delegate = new PriorityMap4Map2Bean();
return delegate.map2Bean(type, map);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
针对多种实现类的选择,我们这里还可以优化,引入委托代理类
/**
* Created by it
* Created in 2019年3月26日
* Description: 路由选择实现方式,这是委托代理模式
*/
public class RouteMap2Bean implements AbstractMap2Bean {
private AbstractMap2Bean delegate;
public RouteMap2Bean() {
this(false);
}
/**
* 超过二个需要定义常量类型来区别
*/
public RouteMap2Bean(boolean mapPriority) {
if (mapPriority) {
this.delegate = new PriorityMap4Map2Bean();
} else {
this.delegate = new DefaultMap2Bean();
}
}
@Override
public <T> T map2Bean(Class<T> type, Map<String, Object> map) throws Exception {
return delegate.map2Bean(type, map);
}
}
修改工具类如下
/**
* Created by it
* Created in 2019年3月26日
* Description: 提供bean转换
*/
public class PropertyUtils {
/**
* Map -> bean
*/
public static <T> T map2Bean(Class<T> type, Map<String, Object> map) {
return map2Bean(type, map, false);
}
public static <T> T map2Bean(Class<T> type, Map<String, Object> map, boolean mapPriority) {
try {
AbstractMap2Bean delegate = new RouteMap2Bean(mapPriority);
return delegate.map2Bean(type, map);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
优雅案例二
装饰者扩展功能
利用装饰者动态增强原对象的功能,实现对文件加解密的封装,将加解密封装在包装对象中,对外提供包装对象来加解密,提供测试代码,十分优雅
加密实现
/**
*
* Created by it
* Created in 2019年3月31日
* Description: 加密包装者文件流
*/
public class DesEncryptOutputStream extends FilterOutputStream{
public DesEncryptOutputStream(OutputStream out) {
super(out);
}
public void encrypt(byte[] buffers) throws IOException {
try {
String encrypt = AESUtil.encrypt(new String(buffers), Keys.DES);
super.write(encrypt.getBytes());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
加密实现
/**
*
* Created by it
* Created in 2019年3月31日
* Description: 解密包装者文件流
*/
public class DesDecryptptInputStream extends FilterInputStream {
protected DesDecryptptInputStream(InputStream in) {
super(in);
}
public byte[] decrypt() {
try {
// 原加密数据大小
int size = in.available();
byte[] data = new byte[size];
super.read(data);
// 解密
String decrypt = AESUtil.decrypt(new String(data), Keys.DES);
return decrypt.getBytes();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
main测试代码,使用上十分优雅
public class Test {
public static void main(String[] args) throws Exception {
String name = "张阿斯kjkjlk就立刻京东方12345";
// 加密
DesEncryptOutputStream outputStream = new DesEncryptOutputStream(new FileOutputStream("1.txt"));
outputStream.encrypt(name.getBytes());
outputStream.close();
// 解密
DesDecryptptInputStream inputStream = new DesDecryptptInputStream(new FileInputStream("1.txt"));
byte[] decrypt = inputStream.decrypt();
System.out.println(new String(decrypt));
inputStream.close();
}
}
优雅案例三
再举一个之前写过的代码
优雅的工具类实现。借鉴TimeUnit实现
public enum CompressUtil {
DEFLATER {
Compress compress = new DeflaterCompress();
public byte[] compress(byte[] data) throws IOException {
return compress.compress(data);
}
public byte[] uncompress(byte[] data) throws IOException {
return compress.uncompress(data);
}
},
BZIP2 {
Compress compress = new LzoCompress();
public byte[] compress(byte[] data) throws IOException {
return compress.compress(data);
}
public byte[] uncompress(byte[] data) throws IOException {
return compress.uncompress(data);
}
},
GZIP {
Compress compress = new GzipCompress();
public byte[] compress(byte[] data) throws IOException {
return compress.compress(data);
}
public byte[] uncompress(byte[] data) throws IOException {
return compress.uncompress(data);
}
},
LZ4 {
Compress compress = new Lz4Compress();
public byte[] compress(byte[] data) throws IOException {
return compress.compress(data);
}
public byte[] uncompress(byte[] data) throws IOException {
return compress.uncompress(data);
}
},
LZO {
Compress compress = new LzoCompress();
public byte[] compress(byte[] data) throws IOException {
return compress.compress(data);
}
public byte[] uncompress(byte[] data) throws IOException {
return compress.uncompress(data);
}
},
SNAPPY {
Compress compress = new SnappyCompress();
public byte[] compress(byte[] data) throws IOException {
return compress.compress(data);
}
public byte[] uncompress(byte[] data) throws IOException {
return compress.uncompress(data);
}
};
public byte[] compress(byte[] data) throws IOException {
throw new AbstractMethodError();
}
public byte[] uncompress(byte[] data) throws IOException {
throw new AbstractMethodError();
}
}
两种不同的调用,十分优雅
CompressUtil.GZIP.compress(bytes);
CompressUtil.LZ4.compress(bytes);
java中常用的压缩与解压具体实现: https://blog.csdn.net/dengjili/article/details/86554012
待续…