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

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

作者: _风听雨声 | 来源:发表于2020-04-08 18:19 被阅读0次

    引言

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

    class StagefrightPlayerFactory :
        public MediaPlayerFactory::IFactory {
      public:
        virtual float scoreFactory(const sp<IMediaPlayer>& 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<MediaPlayerBase> createPlayer() {
            ALOGV(" create StagefrightPlayer");
            return new StagefrightPlayer();
        }
    };
    class NuPlayerFactory : public MediaPlayerFactory::IFactory {
      public:
        virtual float scoreFactory(const sp<IMediaPlayer>& 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<IMediaPlayer>& client,
                                   const sp<IStreamSource> &source,
                                   float curScore) {
            return 1.0;
        }
        virtual sp<MediaPlayerBase> createPlayer() {
            ALOGV(" create NuPlayer");
            return new NuPlayerDriver;
        }
    };
    class SonivoxPlayerFactory : public MediaPlayerFactory::IFactory {
      public:
        virtual float scoreFactory(const sp<IMediaPlayer>& 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<IMediaPlayer>& 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<MediaPlayerBase> 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<? extends IStorageHolder> 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的方法,新增类型对原代码只是新增,改动量小。能很好的解决前两种工厂模式中出现的问题,也符合了开闭原则。


    总结

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

    相关文章

      网友评论

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

          本文链接:https://www.haomeiwen.com/subject/ajrtmhtx.html