(3) 为实现类定义初始化工厂类
class ImageLoaderFactory { private static ImageLoader mImageLoader; private ImageLoaderFactory() { //no instance } /** * @return */ public static ImageLoader createImageLoader(String implClass) { if (mImageLoader == null) { mImageLoader = createImageLoaderWithClassName(implClass); } return mImageLoader; } /** * 此处使用类反射, 所有implClass都不能混淆, 类名必须keep: {@code -keep class a.b.c.ImplClass} * @param implClass 实现类有: FrescoImageLoader, GlideImageLoader, PicassoImageLoader, UILImageLoader * @return */ private static ImageLoader createImageLoaderWithClassName(String implClass) { try { Class klass = Class.forName(implClass); Constructor constructor = klass.getDeclaredConstructor(); if (constructor == null) { throw new RuntimeException(implClass + " 的实现类必须有一个无参构造方法 !"); } boolean isAccessible = constructor.isAccessible(); constructor.setAccessible(true); Object obj = constructor.newInstance(); constructor.setAccessible(isAccessible); if ( !(obj instanceof ImageLoader) ) { throw new RuntimeException(implClass + "必须实现" + ImageLoader.class.getName() + "接口"); } ImageLoader imageLoader = (ImageLoader) obj; return imageLoader; } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return null; } } |
(4) 要使用ImageLoader, 直接用工厂类创建即可, 我们只需要知道实现类的名称, 其它细节都不需要知道. 实现类都是高度内聚, 外部完全不知道其内部的逻辑. 外部只需要调用接口的方法实现业务逻辑即可. 下面是ImageLoader及其相关实现的整体结构:
接口与实现分离, 隐藏实现
(5) 下面是使用工厂类创建ImageLoader实现的代码
import android.content.Context; public final class ImageManager { private static String TAG = "ImageManager"; private static ImageLoader sImageLoader; private ImageManager() { //no instance } public static void init(Context appContext) { if (sImageLoader != null) { throw new IllegalStateException(TAG + " already initalized"); } sImageLoader = ImageLoaderFactory.createImageLoader("com.stone.app.manager.imageloader.internal.FrescoImageLoader"); sImageLoader.init(appContext); } public static ImageLoader getImageLoader() { return sImageLoader; } } |
总结:
将接口和实现类分离, 接口和实现分别放在单独的包中, 并且实现类定义为包私有的 (即类没有修饰符).
定义工厂类, 使用反射初始化实现类.
注意混淆的时候不能混淆实现类的类名, 因为其初始化使用了反射.
有一个设计模式也是分离接口和实现并使其各自独立变化, 那就是桥接模式. 具体可以参考Android中的Window和Context的设计. 关于动态扩展和分离接口和实现, 可以参考《在Android上使用SPI机制》