在前面的几篇文章里面,我们讲了关于文件的使用https://www.jianshu.com/p/36fc304f1ab8,SharedPreference的使用https://www.jianshu.com/p/784450ae7df9,SQLite数据库的使用https://www.jianshu.com/p/95901ccfc54c等等,这些都是属于数据持久化的系列,但是这些都是孤立的、零散的知识节点,很多时候我们需要学会将零散的知识点进行整合,然后通过各种设计模式对外暴露接口供应用层调用,那么,今天我们就来看看如何将之前的数据化内容进行整合。
在开始之前,我们需要先了解一下Java中23种设计模式之一的工厂模式,因为本篇的重点并不在这里,所以我就稍微带一下就好。
工厂模式的实现分为3种:
(1)简单工厂
(2)工厂方法
(3)抽象工厂
简单工厂
这是简单工厂的结构图,其实不难看出,sample为抽象接口,定义每一个具体实现类的规范,而Factory是用来生成sample的具体实例供外部去使用,举一个例子:
public abstract class Computer {
public abstract String getRAM();
public abstract String getHDD();
public abstract String getCPU();
@Override
public String toString(){
return "RAM= "+this.getRAM()+", HDD="+this.getHDD()+", CPU="+this.getCPU();
}}
Computer 为一个抽象的电脑类,里面定义了CPU、RAM、HDD这几个参数,然后它的实现类则为:
Dell电脑类
public class DellComputer extends Computer {
private String ram;
private String hdd;
private String cpu;
public DellComputer(String ram, String hdd, String cpu){
this.ram=ram;
this.hdd=hdd;
this.cpu=cpu;
}
@Override
public String getRAM() {
return this.ram;
}
@Override
public String getHDD() {
return this.hdd;
}
@Override
public String getCPU() {
return this.cpu;
}
}
Apple电脑类
public class AppleComputer extends Computer {
private String ram;
private String hdd;
private String cpu;
public AppleComputer(String ram, String hdd, String cpu){
this.ram=ram;
this.hdd=hdd;
this.cpu=cpu;
}
@Override
public String getRAM() {
return this.ram;
}
@Override
public String getHDD() {
return this.hdd;
}
@Override
public String getCPU() {
return this.cpu;
}
}
编写工厂类供外部调用
public class ComputerFactory {
public static Computer getComputer(String type, String ram, String hdd, String cpu) {
if ("DELL".equalsIgnoreCase(type)) {
return new DellComputer(ram, hdd, cpu);
} else if ("Apple".equalsIgnoreCase(type)) {
return new AppleComputer(ram, hdd, cpu);
}
return null;
}}
最后简单测试一下
public class TestFactory {
public static void main(String[] args) {
Computer dell= ComputerFactory.getComputer("DELL", "2 GB", "500 GB", "2.4 GHz");
Computer apple= ComputerFactory.getComputer("Apple", "16 GB", "1 TB", "2.9 GHz");
System.out.println("Factory DELL Config::" + dell);
System.out.println("Factory APPLE Config::" + apple);
}
}
这样一个简单的简单工厂就完成了。工厂方法和抽象工厂这里就不展开讲解了,有兴趣的同学可以自己去学习学习。
开始进入正题
按照简单工厂的结构,首先我们需要定义一个抽象类去约束具体实现规则,抽象类或者接口都可以,这里我定义的是一个接口,如下所示:
/**
* Created by zhoufan on 2018/2/24.
* 实现对数据的存储
*/
public interface IOHandler {
// 保存String类型
IOHandler saveString(String key, String value);
// 保存Float类型
IOHandler saveFloat(String key, float value);
// 保存Int类型
IOHandler saveInt(String key, int value);
// 保存Boolean类型
IOHandler saveBoolean(String key, boolean value);
// 保存Long类型
IOHandler saveLong(String key, long value);
// 获取String类型的值
String getString(String key);
// 获取Float类型的值
float getFloat(String key, float defaultValue);
// 获取Int类型的值
int getInt(String key, int defaultValue);
// 获取Boolean类型的值
boolean getBoolean(String key, boolean defaultValue);
// 获取Long类型的值
long getLong(String key, long defaultValue);
// 执行删除操作
void delete(String key);
// 更新文件的名称
void updateFileName(String fileName);
}
然后去实现具体的子类。
实现File文件类的存储
/**
* author: zhoufan
* data: 2021/8/9 10:21
* content: 对文件的操作进行进一步的封装
*/
public class FileUtil implements IOHandler {
// 使用单例生成唯一实例
private static volatile FileUtil mInstance;
private String mFileName;
public static FileUtil getInstance() {
if (mInstance == null) {
synchronized (IOFactoryUtil.class) {
if (mInstance == null) {
mInstance = new FileUtil();
}
}
}
return mInstance;
}
private FileUtil() {
mFileName = "fileCache";
}
@Override
public IOHandler saveString(String key, String value) {
BufferedWriter bufferedWriter = null;
try {
boolean isResult = FileTool.createFolderAndFileItemDir(mFileName, key);
if (isResult) {
FileWriter fileWriter = new FileWriter(key);
bufferedWriter = new BufferedWriter(fileWriter);
bufferedWriter.write(value);
bufferedWriter.flush();
} else {
MyToast.showCenterSortToast(IApplication.getContext(), IApplication.getContext().getString(R.string.create_error));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (bufferedWriter != null) {
bufferedWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return this;
}
@Override
public IOHandler saveFloat(String key, float value) {
MyToast.showCenterSortToast(IApplication.getContext(), IApplication.getContext().getString(R.string.file_type_error));
return this;
}
@Override
public IOHandler saveInt(String key, int value) {
MyToast.showCenterSortToast(IApplication.getContext(), IApplication.getContext().getString(R.string.file_type_error));
return this;
}
@Override
public IOHandler saveBoolean(String key, boolean value) {
MyToast.showCenterSortToast(IApplication.getContext(), IApplication.getContext().getString(R.string.file_type_error));
return this;
}
@Override
public IOHandler saveLong(String key, long value) {
MyToast.showCenterSortToast(IApplication.getContext(), IApplication.getContext().getString(R.string.file_type_error));
return this;
}
@Override
public String getString(String key) {
BufferedReader bufferedReader = null;
StringBuilder builder = new StringBuilder();
try {
String path = FileTool.getItemDirPath() + key;
File file = new File(path);
if (file.exists()) {
FileReader fileReader = new FileReader(file);
bufferedReader = new BufferedReader(fileReader, 512);
String readBuff = null;
while ((readBuff = bufferedReader.readLine()) != null) {
builder.append(readBuff);
}
} else {
MyToast.showCenterSortToast(IApplication.getContext(), IApplication.getContext().getString(R.string.file_no_exists));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (bufferedReader != null) {
bufferedReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return builder.toString();
}
@Override
public float getFloat(String key, float defaultValue) {
MyToast.showCenterSortToast(IApplication.getContext(), IApplication.getContext().getString(R.string.file_type_error));
return 0;
}
@Override
public int getInt(String key, int defaultValue) {
MyToast.showCenterSortToast(IApplication.getContext(), IApplication.getContext().getString(R.string.file_type_error));
return 0;
}
@Override
public boolean getBoolean(String key, boolean defaultValue) {
MyToast.showCenterSortToast(IApplication.getContext(), IApplication.getContext().getString(R.string.file_type_error));
return false;
}
@Override
public long getLong(String key, long defaultValue) {
MyToast.showCenterSortToast(IApplication.getContext(), IApplication.getContext().getString(R.string.file_type_error));
return 0;
}
@Override
public void delete(String key) {
FileTool.deleteFile(key);
}
@Override
public void updateFileName(String fileName) {
this.mFileName = fileName;
}
}
实现MMKV的存储
/**
* author: zhoufan
* data: 2021/8/8 9:29
* content: 数据持久化过程中使用MMKV进行存储
*/
public class MMKVUtil implements IOHandler {
// 使用单例生成唯一实例
private static volatile MMKVUtil mInstance;
private MMKV mMMKV;
public static MMKVUtil getInstance() {
if (mInstance == null) {
synchronized (IOFactoryUtil.class) {
if (mInstance == null) {
mInstance = new MMKVUtil();
}
}
}
return mInstance;
}
private MMKVUtil() {
mMMKV = MMKV.defaultMMKV();
}
@Override
public IOHandler saveString(String key, String value) {
if (key == null || value == null) {
return this;
}
mMMKV.encode(key, value);
return this;
}
@Override
public IOHandler saveFloat(String key, float value) {
if (key == null) {
return this;
}
mMMKV.encode(key, value);
return this;
}
@Override
public IOHandler saveInt(String key, int value) {
if (key == null) {
return this;
}
mMMKV.encode(key, value);
return this;
}
@Override
public IOHandler saveBoolean(String key, boolean value) {
if (key == null) {
return this;
}
mMMKV.encode(key, value);
return this;
}
@Override
public IOHandler saveLong(String key, long value) {
if (key == null) {
return this;
}
mMMKV.encode(key, value);
return this;
}
@Override
public String getString(String key) {
if (key == null) {
return null;
}
return mMMKV.decodeString(key);
}
@Override
public float getFloat(String key, float defaultValue) {
if (key == null) {
return defaultValue;
}
return mMMKV.decodeFloat(key);
}
@Override
public int getInt(String key, int defaultValue) {
if (key == null) {
return defaultValue;
}
return mMMKV.decodeInt(key);
}
@Override
public boolean getBoolean(String key, boolean defaultValue) {
if (key == null) {
return defaultValue;
}
return mMMKV.decodeBool(key);
}
@Override
public long getLong(String key, long defaultValue) {
if (key == null) {
return defaultValue;
}
return mMMKV.decodeLong(key);
}
@Override
public void delete(String key) {
mMMKV.removeValueForKey(key);
}
@Override
public void updateFileName(String fileName) {
mMMKV = MMKV.mmkvWithID(fileName);
}
}
实现SharedPreference的存储
public class SharePreferencesUtil implements IOHandler {
// 使用单例生成唯一实例
private static volatile SharePreferencesUtil mInstance;
private String mFileName;
public static SharePreferencesUtil getInstance() {
if (mInstance == null) {
synchronized (IOFactoryUtil.class) {
if (mInstance == null) {
mInstance = new SharePreferencesUtil();
}
}
}
return mInstance;
}
private SharePreferencesUtil() {
mFileName = "sharedPreferenceCache";
}
@Override
public SharePreferencesUtil saveString(String key, String value) {
SharedPreferences sharedPreferences = IApplication.getContext().getSharedPreferences(mFileName, 0);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(key, value);
editor.apply();
return this;
}
@Override
public SharePreferencesUtil saveFloat(String key, float value) {
SharedPreferences sharedPreferences = IApplication.getContext().getSharedPreferences(mFileName, 0);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putFloat(key, value);
editor.apply();
return this;
}
@Override
public SharePreferencesUtil saveInt(String key, int value) {
SharedPreferences sharedPreferences = IApplication.getContext().getSharedPreferences(mFileName, 0);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putInt(key, value);
editor.apply();
return this;
}
@Override
public SharePreferencesUtil saveBoolean(String key, boolean value) {
SharedPreferences sharedPreferences = IApplication.getContext().getSharedPreferences(mFileName, 0);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean(key, value);
editor.apply();
return this;
}
@Override
public SharePreferencesUtil saveLong(String key, long value) {
SharedPreferences sharedPreferences = IApplication.getContext().getSharedPreferences(mFileName, 0);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putLong(key, value);
editor.apply();
return this;
}
@Override
public String getString(String key) {
SharedPreferences sharedPreferences = IApplication.getContext().getSharedPreferences(mFileName, 0);
return sharedPreferences.getString(key, null);
}
@Override
public float getFloat(String key, float defaultValue) {
SharedPreferences sharedPreferences = IApplication.getContext().getSharedPreferences(mFileName, 0);
return sharedPreferences.getFloat(key, defaultValue);
}
@Override
public int getInt(String key, int defaultValue) {
SharedPreferences sharedPreferences = IApplication.getContext().getSharedPreferences(mFileName, 0);
return sharedPreferences.getInt(key, defaultValue);
}
@Override
public boolean getBoolean(String key, boolean defaultValue) {
SharedPreferences sharedPreferences = IApplication.getContext().getSharedPreferences(mFileName, 0);
return sharedPreferences.getBoolean(key, defaultValue);
}
@Override
public long getLong(String key, long defaultValue) {
SharedPreferences sharedPreferences = IApplication.getContext().getSharedPreferences(mFileName, 0);
return sharedPreferences.getLong(key, defaultValue);
}
// 执行删除操作
@Override
public void delete(String key) {
try {
SharedPreferences sharedPreferences = IApplication.getContext().getSharedPreferences(mFileName, 0);
SharedPreferences.Editor editor = sharedPreferences.edit();
if (sharedPreferences.contains(key)) {
editor.remove(key);
editor.apply();
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void updateFileName(String fileName) {
this.mFileName = fileName;
}
}
也就是说,FileUtil(文件存储)、MMKVUtil(MMKV存储)、SharedPreferenceUtil(SharedPreference存储)就是IOHandler的具体实现类,类似于上面图中的sampleA、sampleB等等。接下来要操作的就是我们的Factory了。
首先定义工厂的抽象类
public interface IOFactory {
IOHandler create(String type);
}
然后去实现我们的工厂,在这里提供对外的实现类
/**
* Created by zhoufan on 2018/2/24.
* 使用抽象工厂方法实现对缓存的处理
*/
public class IOFactoryUtil implements IOFactory {
// 使用单例生成唯一实例
private static volatile IOFactoryUtil ioFactoryUtil;
public static final String MMKV_HANDLER = "1";
public static final String SHAREDPREFERENCE_HANDLER = "2";
public static final String FILE_HANDLER = "3";
private IOHandler mIOHandler;
public static IOFactoryUtil getIOFactoryUtil() {
if (ioFactoryUtil == null) {
synchronized (IOFactoryUtil.class) {
if (ioFactoryUtil == null) {
ioFactoryUtil = new IOFactoryUtil();
}
}
}
return ioFactoryUtil;
}
@Override
public IOHandler create(String type) {
switch (type) {
case SHAREDPREFERENCE_HANDLER:
mIOHandler = getSharePreferencesHandler();
case FILE_HANDLER:
mIOHandler = getFileHandler();
default:
mIOHandler = getMMKVHandler();
}
return mIOHandler;
}
// SharePreferences存储
private IOHandler getSharePreferencesHandler() {
return SharePreferencesUtil.getInstance();
}
// MMKV存储
private IOHandler getMMKVHandler() {
return MMKVUtil.getInstance();
}
// 文件存储
private IOHandler getFileHandler() {
return FileUtil.getInstance();
}
// 默认的存储方式
public IOHandler getUserHandler() {
return create(MMKV_HANDLER);
}
}
代码写的很详细,就不做过多讲解了,到这里,通过一个简单工厂就实现了对数据持久化实现的简单封装,最后来看下实现
// 使用默认的数据存储方式(默认为MMKV)
IOFactoryUtil.getIOFactoryUtil().userHandler.saveString("key","value")
// 切换引擎进行数据存储
IOFactoryUtil.getIOFactoryUtil().create(IOFactoryUtil.SHAREDPREFERENCE_HANDLER).saveString("key","value")
这样,一个简单又好用的数据持久化就完成啦