策略模式

2022-12-05  本文已影响0人  古早味蛋糕
1、 策略模式介绍

Android每一种模块都有很多种解决方案,例如网络模块有OKHttp、Volley、Retrofit等;数据库有OrmLite、GreenDao、Room等;图片模块有Glide、Picaso等。平时开发的时候可能就会选定一种模块,例如图片就用Glide,然后在项目的代码里面直接调用Glide的接口来完成图片的处理。
如果确定以后不会更换这些模块的话,那么初看也没什么问题。但是万一以后有了一个更好的解决方案呢?或者公司开发了一个中间件用来解决这个模块的问题,然后公司通知各个项目都需要接入这个模块。
这种情况下,我们通常的解决方案是:将项目中所有用到原先模块的API,统一换成新引入模块的API。这样不仅工程量大,还容易造成新的问题;而且新的模块的API也需要重新了解和熟悉。

2、策略模式实现

根据设计模式中的“开闭原则”,应该尽量做到对修改关闭。如果使用上述提到的解决方案,那么相当于是业务跟模块之间强耦合了。
那么怎么解决这种“强耦合”呢?答案是面向接口编程。
在使用模块功能的时候,尽量不要直接使用模块提供的API接口,而要使用自定义的接口提供的方法,也就是通常所说的面向接口编程。
具体的解决方案如下:

接下来我们创建两个日志功能类,分别实现上面的日志接口。
第一个日志功能类使用系统自带的log实现,我们定义为DefaultLogProcessor:

public class DefaultLogProcessor implements ILogProcessor {
    @Override
    public void v(String vLog) {
        Log.v("DefaultLogProcessor", "defaultlog:" + vLog);
    }

    @Override
    public void d(String dLog) {
        Log.d("DefaultLogProcessor", "defaultlog:" + dLog);
    }

    @Override
    public void i(String iLog) {
        Log.i("DefaultLogProcessor", "defaultlog:" + iLog);
    }

    @Override
    public void e(String eLog) {
        Log.e("DefaultLogProcessor", "defaultlog:" + eLog);
    }
}

第二个日志功能类使用ZydLog实现,我们定义为ZydLogProcessor:

public class ZydLogProcessor implements ILogProcessor {
    @Override
    public void v(String vLog) {
        ZydLog.v("zydlog:" + vLog);
    }

    @Override
    public void d(String dLog) {
        ZydLog.d("zydlog:" + dLog);
    }

    @Override
    public void i(String iLog) {
        ZydLog.i("zydlog:" + iLog);
    }

    @Override
    public void e(String eLog) {
        ZydLog.e("zydlog:" + eLog);
    }
}

提供一个使用类LogLoader:

public class LogLoader implements ILogProcessor {

    private static volatile LogLoader sInstance = null;
    private static ILogProcessor sILogProcessor;

    private LogLoader() {

    }

    public static LogLoader getInstance() {
        if (sInstance == null) {
            synchronized (LogLoader.class) {
                if (sInstance == null) {
                    sInstance = new LogLoader();
                }
            }
        }
        return sInstance;
    }

    //通过load选定使用哪一个日志功能类
    public static ILogProcessor load(ILogProcessor logProcessor) {
        return sILogProcessor = logProcessor;
    }

    @Override
    public void v(String vLog) {
        sILogProcessor.v(vLog);
    }

    @Override
    public void d(String dLog) {
        sILogProcessor.d(dLog);
    }

    @Override
    public void i(String iLog) {
        sILogProcessor.i(iLog);
    }

    @Override
    public void e(String eLog) {
        sILogProcessor.e(eLog);
    }
}

这个LogLoader直接使用了ILogProcessor接口提供的方法作为对外API接口的调用入口。
这种使用方式保持了调用的接口名称和ILogProcessor一致。不过有个缺点就是LogLoader必须要实现接口,而且接口名称不能发生变化。
也可以实现另一种LogLoader,不用实现ILogProcessor。自定义对外的API接口方法的名称,其灵活性更强。

public class LogLoader2 {

    private static volatile LogLoader2 sInstance = null;
    private static ILogProcessor sILogProcessor;

    private LogLoader2() {

    }

    public static LogLoader2 getInstance() {
        if (sInstance == null) {
            synchronized (LogLoader2.class) {
                if (sInstance == null) {
                    sInstance = new LogLoader2();
                }
            }
        }
        return sInstance;
    }

    public static ILogProcessor load(ILogProcessor logProcessor) {
        return sILogProcessor = logProcessor;
    }

    public void useVmode(String vLog) {
        sILogProcessor.v(vLog);
    }

    public void useDmode(String dLog) {
        sILogProcessor.d(dLog);
    }

    public void useImode(String iLog) {
        sILogProcessor.i(iLog);
    }

    public void useEmode(String eLog) {
        sILogProcessor.e(eLog);
    }
}
最后使用日志模块的策略模式:
    LogLoader.load(new ZydLogProcessor());
    LogLoader.getInstance().d("this is zyd log");
    LogLoader.load(new DefaultLogProcessor());
    LogLoader.getInstance().d("this is system default log");

通过LogLoader.load(……)可以自由切换不同的日志实现模块,在使用的地方无须做任何改动,仍然使用LogLoader.getInstance().d(……)方法。

上一篇 下一篇

猜你喜欢

热点阅读