android - 如何使用(智能引用)代理设计模式实现缓存机制?

标签 android oop design-patterns software-design proxy-pattern

目前,我正在进行我的学术研究,我通过尽可能实现四人组设计模式来设计一个 Android 应用程序(注意:GoF 模式是必须的,它是我进行的研究的一部分)。

现在我来到了通过 Repository 从远程/Rest API 获取数据的部分。我不希望应用程序总是从远程获取完全相同的数据,因为这非常昂贵(消耗时间、资源、带宽等),就像大多数应用程序一样,我决定添加缓存机制。

在我之前的 android 应用程序项目中,我通常使用数据库 (Room) 结合专用字段“缓存”数据,以保持缓存对象保留在内存中(参见下面的代码 fragment )。

但是,我几乎没有时间(由于研究截止日期),我想更多地关注 GoF 在我设计的应用程序上的实现,并且更愿意避免与数据库相关的东西。

下面的代码是我的 Repository 类的 fragment 。当我(比方说一个 ViewModel)需要用户数据时,它将调用存储库中的 getUser() 方法。

getUser() 方法中,我将检查 shouldRefresh 是否为 false 以及缓存对象是否为空。一旦为真,它将返回 cacheUser,但如果为假,则将调用 fetchUser() 方法(改造库提供的接口(interface))。我会认为 fetchUser() 执行一项非常繁重且昂贵的任务(因为它需要互联网并且该过程取决于网络质量)。

Repository.java 类的 fragment 。

public class AccountRepository {
    private AccountWebservice webservice;
    private User cacheUser;

    public User getUser(String accessToken, int userId, boolean shouldRefresh) {
        if (!shouldRefresh && cacheUser != null) {
            return cacheUser;
        } 

        Call<SinglePayloadResponse<User>> call = webservice.fetchUser(accessToken, userId);
        call.enqueue(new Callback<SinglePayloadResponse<User>>() {
        @Override
        public void onResponse(Call<SinglePayloadResponse<User>> call, Response<SinglePayloadResponse<User>> response) {
            assert response.body() != null;
            cacheUser = response.body().getPayload(); // currently I'm *caching* the response by assign it to cacheUser
            return cacheUser;
        }

        @Override
        public void onFailure(Call<SinglePayloadResponse<User>> call, Throwable t) {

        }
    });
    }
}

我发现代理模式(Smart Proxy Pattern)用于处理昂贵对象的创建,如本例(Usage of Proxy design pattern)所示,正如我们所见,引入了 ProxyImage 来包装真正的昂贵对象(RealImage ) 如果已经加载则不再重新加载。

我看到智能代理模式具有我希望在此应用程序中完成的行为(如缓存)。我想知道我是否可以实现此模式以从 Repository 类中的 Web 服务缓存响应(如用户数据、最近查看的产品、最近的搜索结果和其他需要尽快访问的相关内容)。

现在是真正的问题:

我的情况是否足够合理以应用智能代理模式?如果可以,如何应用? (让我们以上面的存储库类的 fragment 为例,这是我目前访问用户数据的解决方案,我需要应用智能代理模式)

我还是努力去学习GoF模式的23个目录,由于时间有限,知识有限,视角有限,很容易漏掉一些关于模式的东西,甚至是重要的东西。因此,感谢任何对“我的”或“您的”误解的回答、建议和澄清,谢谢。

最佳答案

要使用代理,您首先需要创建一个接口(interface)。由于您已经使用了名称“AccountRepository”,因此我将调用接口(interface)“IAccountRepository

public interface IAccountRepository {
    User getUser(String accessToken, int userId, boolean shouldRefresh);
}

然后让 AccountRepository 实现 IAccountRepository 并从那里移出所有与缓存相关的逻辑:

public class AccountRepository implements IAccountRepository {
    private AccountWebservice webservice;

    public User getUser(String accessToken, int userId, boolean shouldRefresh) {
        Call<SinglePayloadResponse<User>> call = webservice.fetchUser(accessToken, userId);
        call.enqueue(new Callback<SinglePayloadResponse<User>>() {
        @Override
        public void onResponse(Call<SinglePayloadResponse<User>> call, Response<SinglePayloadResponse<User>> response) {
            assert response.body() != null;
            cacheUser = response.body().getPayload(); // currently I'm *caching* the response by assign it to cacheUser
            return cacheUser;
        }

        @Override
        public void onFailure(Call<SinglePayloadResponse<User>> call, Throwable t) {

        }
    });
    }
}

现在你可以实现你的代理了:

public AccountRepositoryCacheProxy implements IAccountRepository {
     private IAccountRepository accountRepository
     public User getUser(String accessToken, int userId, boolean shouldRefresh) {
           if (!userIsInCache(userId) || shouldRefresh) {
                User result = accountRepository.GetUser(accessToken, userId, false);
                addUserInCache(userId, result);
                return result;
           }
           return userFromCache(userid);
     }
}

您的实际缓存应该类似于 String、User 的并发字典。

在您的代码中任何需要帐户存储库的地方,您都需要以这种方式创建它:

 IAccountRepository accountRepository = new AccountRepositoryCacheProxy( new AccountRepository()));

实际上依赖注入(inject)系统会好得多。

关于android - 如何使用(智能引用)代理设计模式实现缓存机制?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62847149/

相关文章:

android - 如何使用 Picasso lib 在 ImageView 上放大和调整图像

android - 错误 : ENOENT: no such file or directory when running Ionic Cordova Platform Add Android

python - 如何在python中强制属性为int?

javascript - jQuery startInterval 和clearInterval 在不同的函数中

php - 如何从框架外部访问OpenCart功能?

.net - 领域驱动设计 : How to access child of aggregate root

android - SharedPreferences 不保存/持久化

android - 浏览 Android SQLite 数据库中的数据

algorithm - 在不重复逻辑的情况下对项目进行分组

数组中的 C++ CRTP