工厂设计模式-增加代码可扩展性-数据存储例子

引言

工厂设计模式在Android系统源码中也经常能见到,如BitmapFactory,传入不同的参数类型,都是得到一个Bitmap对象。还有MediaPlayerFactory,在MediaPlayerFactory的体现更加直观。

class StagefrightPlayerFactory :
    public MediaPlayerFactory::IFactory {
  public:
    virtual float scoreFactory(const sp& client,
                               int fd,
                               int64_t offset,
                               int64_t length,
                               float curScore) {
        char buf[20];
        lseek(fd, offset, SEEK_SET);
        read(fd, buf, sizeof(buf));
        lseek(fd, offset, SEEK_SET);
        long ident = *((long*)buf);
        // Ogg vorbis?
        if (ident == 0x5367674f) // 'OggS'
            return 1.0;
        return 0.0;
    }
    virtual sp createPlayer() {
        ALOGV(" create StagefrightPlayer");
        return new StagefrightPlayer();
    }
};
class NuPlayerFactory : public MediaPlayerFactory::IFactory {
  public:
    virtual float scoreFactory(const sp& client,
                               const char* url,
                               float curScore) {
        static const float kOurScore = 0.8;
        if (kOurScore <= curScore)
            return 0.0;
        if (!strncasecmp("http://", url, 7)
                || !strncasecmp("https://", url, 8)) {
            size_t len = strlen(url);
            if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
                return kOurScore;
            }
            if (strstr(url,"m3u8")) {
                return kOurScore;
            }
        }
        if (!strncasecmp("rtsp://", url, 7)) {
            return kOurScore;
        }
        return 0.0;
    }
    virtual float scoreFactory(const sp& client,
                               const sp &source,
                               float curScore) {
        return 1.0;
    }
    virtual sp createPlayer() {
        ALOGV(" create NuPlayer");
        return new NuPlayerDriver;
    }
};
class SonivoxPlayerFactory : public MediaPlayerFactory::IFactory {
  public:
    virtual float scoreFactory(const sp& client,
                               const char* url,
                               float curScore) {
        static const float kOurScore = 0.4;
        static const char* const FILE_EXTS[] = { ".mid",
                                                 ".midi",
                                                 ".smf",
                                                 ".xmf",
                                                 ".mxmf",
                                                 ".imy",
                                                 ".rtttl",
                                                 ".rtx",
                                                 ".ota" };
        if (kOurScore <= curScore)
            return 0.0;
        // use MidiFile for MIDI extensions
        int lenURL = strlen(url);
        for (int i = 0; i < NELEM(FILE_EXTS); ++i) {
            int len = strlen(FILE_EXTS[i]);
            int start = lenURL - len;
            if (start > 0) {
                if (!strncasecmp(url + start, FILE_EXTS[i], len)) {
                    return kOurScore;
                }
            }
        }
        return 0.0;
    }
    virtual float scoreFactory(const sp& client,
                               int fd,
                               int64_t offset,
                               int64_t length,
                               float curScore) {
        static const float kOurScore = 0.8;
        if (kOurScore <= curScore)
            return 0.0;
        // Some kind of MIDI?
        EAS_DATA_HANDLE easdata;
        if (EAS_Init(&easdata) == EAS_SUCCESS) {
            EAS_FILE locator;
            locator.path = NULL;
            locator.fd = fd;
            locator.offset = offset;
            locator.length = length;
            EAS_HANDLE  eashandle;
            if (EAS_OpenFile(easdata, &locator, &eashandle) == EAS_SUCCESS) {
                EAS_CloseFile(easdata, eashandle);
                EAS_Shutdown(easdata);
                return kOurScore;
            }
            EAS_Shutdown(easdata);
        }
        return 0.0;
    }
    virtual sp createPlayer() {
        ALOGV(" create MidiFile");
        return new MidiFile();
    }
};

MediaPlayerFactory有一个抽象方法createPlayer();

有四个具体实现此方法的子类继承他:

1.StagefrightPlayerFactory

2.MuPlayerFactory

3.SonlvoxPlayerFactory

4.TestPlayerFactory

这四种MediaPlayerFactory分别会生成不同的MediaPlayer基类:StagefrightPlayer、NuPlayerDriver、MidiFile、TestPlayerStub。
可见,工厂设计模式离我们并不遥远。设计模式是一种代码思想,而并非是一种具体的代码。它的代码是可以根据需要去变动的,只有将设计思想融入到实际的开发中,它才是有用的。

工厂设计模式的分类

目前工厂模式的常见的分类主要有3种,简单工厂模式、工厂方法模式,抽象工厂模式。


简单工厂模式
简单工厂模式
public class StorageFactory {
    private static volatile StorageFactory mInstance;

    private StorageFactory() {
    }

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

    public enum StorageType {
        Memory, Disk
    }

    public IStorageHolder createStorageHolder(StorageType storageType) {
        switch (storageType) {
            case Memory:
                return MemoryStorageHolder.getInstance();
            case Disk:
                return new DiskStorageHolder();
            default:
                return null;
        }
    }
}

在上方代码上可以看到,StorageFactory掌握着IStorageHolder实现类的初始化。如果不是经常去增加IStorageHolder实现类的类型,应该简单工厂模式就可以满足解耦的需要。但是如果去新增IStorageHolder实现类的类型,要对原代码改动较大,要去新增type类型,多增加一个case判断,在使用的位置也需要去改动。不符合开闭原则,于是就衍生了工厂方法模式。


工厂方法模式
工厂方法模式
public class StorageFactory {
    private static volatile StorageFactory mInstance;

    private StorageFactory() {
    }

    public static StorageFactory getInstance() {
        if (mInstance == null) {
            synchronized (StorageFactory.class) {
                if (mInstance == null) {
                    mInstance = new StorageFactory();
                }
            }
        }
        return mInstance;
    }
    
    public IStorageHolder createStorageHolder(IStorageFactory iStorageFactory) {
        return iStorageFactory.createStorageFactory();
    }
}
public class DiskStorageFactory implements IStorageFactory{
    @Override
    public IStorageHolder createStorageFactory() {
        return new DiskStorageHolder();
    }
}
public class DiskStorageHolder implements IStorageHolder {
    private DiskLruCacheHelper mDiskLruCacheHelper;

    public DiskStorageHolder(Context context, String uniqueName) {
        if (mDiskLruCacheHelper == null){
            try {
                mDiskLruCacheHelper = new DiskLruCacheHelper(context,uniqueName);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public IStorageHolder save(String key, String value) {
        mDiskLruCacheHelper.put(key,value);
        return this;
    }

    @Override
    public IStorageHolder save(String key, int value) {
        save(key,String.valueOf(value));
        return this;
    }

    @Override
    public IStorageHolder save(String key, Serializable value) {
        mDiskLruCacheHelper.put(key,value);
        return this;
    }

    @Override
    public String getString(String key) {
        return mDiskLruCacheHelper.getAsString(key);
    }

    @Override
    public int getInt(String key) {
        return Integer.parseInt(mDiskLruCacheHelper.getAsString(key));
    }

    @Override
    public Object getSerializable(String key) {
        return mDiskLruCacheHelper.getAsSerializable(key);
    }
    
}

从上方代码可以看到,StorageFactory只有一个创建IStorageHolder的方法createStorageHolder(),这个方法传入的是IStorageFactory,也就是说传入的是一个对象的工厂,再通过这个特定类的对象工厂去创建IStorageHolder。这种模式很好的解决了新增类型需要改动原代码较多的问题,新增类型需要去新增工厂和IStorageHolder的实现类就行。解决了不符合开闭原则的问题。但是目前还有一个问题,如果新增的类型很多,那么要增加的类的数量就会暴涨,且每个类的逻辑都差不多,显然目前的这种方式还是存在问题的。于是就衍生了抽象工厂模式。


抽象工厂模式
抽象工厂模式
public class StorageFactory implements IStorageFactory {
    private static volatile StorageFactory mInstance;
    private IStorageHolder mMemoryHolder, mDiskStorageHolder, mPreferenceStorageHolder;

    private StorageFactory() {
    }

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

    @Override
    public IStorageHolder createStorageHolder(Class cla) {
        try {
            return cla.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public IStorageHolder createMemoryHolder() {
        if (mMemoryHolder == null) {
            mMemoryHolder = createStorageHolder(MemoryStorageHolder.class);
        }
        return mMemoryHolder;
    }

    public IStorageHolder createDiskStorageHolder(Context context, String uniqueName) {
        if (mDiskStorageHolder == null) {
            mDiskStorageHolder = new DiskStorageHolder(context.getApplicationContext(), uniqueName);
        }
        return mDiskStorageHolder;
    }

    public IStorageHolder createPreferenceStorageHolder(Context context) {
        if (mPreferenceStorageHolder == null) {
            mPreferenceStorageHolder = new PreferenceStorageHolder(context);
        }
        return mPreferenceStorageHolder;
    }
}

在上方的代码中可以看到,如果新增类型,需要在StorageFactory中去新增一个获取IStorageHolder的方法,新增类型对原代码只是新增,改动量小。能很好的解决前两种工厂模式中出现的问题,也符合了开闭原则。


总结

任何一种设计模式,他的代码都可以是多变的,只有把设计模式用到对的地方,那么它带来的可扩展性,和代码的可维护性,会是一种比较大的飞跃。

你可能感兴趣的:(工厂设计模式-增加代码可扩展性-数据存储例子)