优雅的解决工具类设计

优雅案例一

问题思考:在考虑设计工具类时候,大多数情况我都习惯的都是涉及为一个类,然后定义一个静态方法,然后通过调用这个静态方法复用,大体如下

举例说明:类型转换工具类,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

待续…

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值