Goodle Clean设计架构

23  * @param <P> the response type
24 */
25 public abstract class UseCase<Q extends UseCase.RequestValues, P extends UseCase.ResponseValue> {
26
27 private Q mRequestValues;
28
29 private UseCaseCallback<P> mUseCaseCallback;
30
31 public void setRequestValues(Q requestValues) {
32 mRequestValues = requestValues;
33 }
34
35 public Q getRequestValues() {
36 return mRequestValues;
37 }
38
39 public UseCaseCallback<P> getUseCaseCallback() {
40 return mUseCaseCallback;
41 }
42
43 public void setUseCaseCallback(UseCaseCallback<P> useCaseCallback) {
44 mUseCaseCallback = useCaseCallback;
45 }
46
47 void run() {
48 executeUseCase(mRequestValues);
49 }
50
51 protected abstract void executeUseCase(Q requestValues);
52
53 /**
54 * Data passed to a request.
55 */
56 public interface RequestValues {
57 }
58
59 /**
60 * Data received from a request.
61 */
62 public interface ResponseValue {
63 }
64
65 public interface UseCaseCallback<R> {
66 void onSuccess(R response);
67 void onError();
68 }
69 }

  实体基类UseCase的设计用了泛型和接口,仅仅设计了两个字段mRequestValues和mUseCaseCallback。其中,mRequestValues代表数据请求参数,用泛型进行了封装,它其实也是一个类的对象;mUseCaseCallback代表请求结果,同样的,它也是一个类的对象,只不过这个类是用接口的形式进行抽象和封装的。同时,UseCase中定义抽象方法executeUseCase()作为实体操作的入口。

  接下来,我们随便看一个UseCase的实现类,就拿ActivateTask来说,ActivateTask继承了UseCase,其实现代码如下:

 1 /*
2 * Copyright 2016, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.example.android.architecture.blueprints.todoapp.tasks.domain.usecase;
18
19 import android.support.annotation.NonNull;
20
21 import com.example.android.architecture.blueprints.todoapp.UseCase;
22 import com.example.android.architecture.blueprints.todoapp.data.source.TasksRepository;
23
24 import static com.google.common.base.Preconditions.checkNotNull;
25
26 /**
27 * Marks a task as active (not completed yet).
28 */
29 public class ActivateTask extends UseCase<ActivateTask.RequestValues, ActivateTask.ResponseValue> {
30
31 private final TasksRepository mTasksRepository;
32
33 public ActivateTask(@NonNull TasksRepository tasksRepository) {
34 mTasksRepository = checkNotNull(tasksRepository, "tasksRepository cannot be null!");
35 }
36
37 @Override
38 protected void executeUseCase(final RequestValues values) {
39 String activeTask = values.getActivateTask();
40 mTasksRepository.activateTask(activeTask);
41 getUseCaseCallback().onSuccess(new ResponseValue());
42 }
43
44 public static final class RequestValues implements UseCase.RequestValues {
45
46 private final String mActivateTask;
47
48 public RequestValues(@NonNull String activateTask) {
49 mActivateTask = checkNotNull(activateTask, "activateTask cannot be null!");
50 }
51
52 public String getActivateTask() {
53 return mActivateTask;
54 }
55 }
56
57 public static final class ResponseValue implements UseCase.ResponseValue { }
58 }

  可以看到,在ActivateTask 中,实现了父类UseCase的两个接口RequestValues 和ResponseValue ,这两个类将分别作为最终的实体请求对象类和返回结果对象类,同时,UseCase中的抽象方法executeUseCase()也被实现。因为实现的代码里面加入了泛型和接口,所以看起来会比较复杂,但是说到底无非就是继承和实现的关系,仅此而已。通过这种面向接口的设计方式,可以让我们的代码看起来结构更清晰、更统一。

  接下来,我们可以看一下这个项目中的任务执行类UseCaseThreadPoolScheduler,同样,UseCaseThreadPoolScheduler的设计采用了面向接口的方式,它实现了seCaseScheduler接口,UseCaseScheduler和UseCaseThreadPoolScheduler的实现分别如下:

 1 /*
2 * Copyright 2016, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.example.android.architecture.blueprints.todoapp;
18
19 /**
20 * Interface for schedulers, see {@link UseCaseThreadPoolScheduler}.
21 */
22 public interface UseCaseScheduler {
23
24 void execute(Runnable runnable);
25
26 <V extends UseCase.ResponseValue> void notifyResponse(final V response,
27 final UseCase.UseCaseCallback<V> useCaseCallback);
28
29 <V extends UseCase.ResponseValue> void onError(
30 final UseCase.UseCaseCallback<V> useCaseCallback);
31 }
 1 /*
2 * Copyright 2016, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.example.android.architecture.blueprints.todoapp;
18
19 import android.os.Handler;
20
21 import java.util.concurrent.ArrayBlockingQueue;
22 import java.util.concurrent.Executors;
23 import java.util.concurrent.ThreadPoolExecutor;
24 import java.util.concurrent.TimeUnit;
25
26 /**
27 * Executes asynchronous tasks using a {@link ThreadPoolExecutor}.
28 * <p>
29 * See also {@link Executors} for a list of factory methods to create common
30 * {@link java.util.concurrent.ExecutorService}s for different scenarios.
31 */
32 public class UseCaseThreadPoolScheduler implements UseCaseScheduler {
33
34 private final Handler mHandler = new Handler();
35
36 public static final int POOL_SIZE = 2;
37
38 public static final int MAX_POOL_SIZE = 4;
39
40 public static final int TIMEOUT = 30;
41
42 ThreadPoolExecutor mThreadPoolExecutor;
43
44 public UseCaseThreadPoolScheduler() {
45 mThreadPoolExecutor = new ThreadPoolExecutor(POOL_SIZE, MAX_POOL_SIZE, TIMEOUT,
46 TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(POOL_SIZE));
47 }
48
49 @Override
50 public void execute(Runnable runnable) {
51 mThreadPoolExecutor.execute(runnable);
52 }
53
54 @Override
55 public <V extends UseCase.ResponseValue> void notifyResponse(final V response,
56 final UseCase.UseCaseCallback<V> useCaseCallback) {
57 mHandler.post(new Runnable() {
58 @Override
59 public void run() {
60 useCaseCallback.onSuccess(response);
61 }
62 });
63 }
64
65 @Override
66 public <V extends UseCase.ResponseValue> void onError(
67 final UseCase.UseCaseCallback<V> useCaseCallback) {
68 mHandler.post(new Runnable() {
69 @Override
70 public void run() {
71 useCaseCallback.onError();
72 }
73 });
74 }
75
76 }

  可以看出,UseCaseThreadPoolScheduler实现了UseCaseScheduler中的三个抽象方法。

  接下来,我们再看看UseCaseHandler这个类,在UseCaseHandler中,通过子类实例化父类的形式,用UseCaseThreadPoolScheduler实例化了UseCaseScheduler对象。UseCaseHandler的代码如下:

/*
* Copyright 2016, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package com.example.android.architecture.blueprints.todoapp; import com.example.android.architecture.blueprints.todoapp.util.EspressoIdlingResource; /**
* Runs {@link UseCase}s using a {@link UseCaseScheduler}.
*/
public class UseCaseHandler { private static UseCaseHandler INSTANCE; private final UseCaseScheduler mUseCaseScheduler; public UseCaseHandler(UseCaseScheduler useCaseScheduler) {
mUseCaseScheduler = useCaseScheduler;
} public <T extends UseCase.RequestValues, R extends UseCase.ResponseValue> void execute(
final UseCase<T, R> useCase, T values, UseCase.UseCaseCallback<R> callback) {
useCase.setRequestValues(values);
useCase.setUseCaseCallback(new UiCallbackWrapper(callback, this)); // The network request might be handled in a different thread so make sure
// Espresso knows
// that the app is busy until the response is handled.
EspressoIdlingResource.increment(); // App is busy until further notice mUseCaseScheduler.execute(new Runnable() {
@Override
public void run() { useCase.run();
// This callback may be called twice, once for the cache and once for loading
// the data from the server API, so we check before decrementing, otherwise
// it throws "Counter has been corrupted!" exception.
if (!EspressoIdlingResource.getIdlingResource().isIdleNow()) {
EspressoIdlingResource.decrement(); // Set app as idle.
}
}
});
} public <V extends UseCase.ResponseValue> void notifyResponse(final V response,
final UseCase.UseCaseCallback<V> useCaseCallback) {
mUseCaseScheduler.notifyResponse(response, useCaseCallback);
} private <V extends UseCase.ResponseValue> void notifyError(
final UseCase.UseCaseCallback<V> useCaseCallback) {
mUseCaseScheduler.onError(useCaseCallback);
} private static final class UiCallbackWrapper<V extends UseCase.ResponseValue> implements
UseCase.UseCaseCallback<V> {
private final UseCase.UseCaseCallback<V> mCallback;
private final UseCaseHandler mUseCaseHandler; public UiCallbackWrapper(UseCase.UseCaseCallback<V> callback,
UseCaseHandler useCaseHandler) {
mCallback = callback;
mUseCaseHandler = useCaseHandler;
} @Override
public void onSuccess(V response) {
mUseCaseHandler.notifyResponse(response, mCallback);
} @Override
public void onError() {
mUseCaseHandler.notifyError(mCallback);
}
} public static UseCaseHandler getInstance() {
if (INSTANCE == null) {
INSTANCE = new UseCaseHandler(new UseCaseThreadPoolScheduler());
}
return INSTANCE;
}
}

  从上面的代码中,我们可以看到,声明的变量mUseCaseScheduler是UseCaseScheduler的对象,但是在构建UseCaseHandler对象的时候,传入的参数却是UseCaseThreadPoolScheduler对象,即用UseCaseThreadPoolScheduler实例化了UseCaseScheduler对象。然后,对mUseCaseScheduler的所有操作都转化成了对UseCaseThreadPoolScheduler对象的操作。

  然后,我们仔细看UseCaseHandler的实现的代码,我们会发现其实对实体进行操作的入口就是execute()方法!因为这个方法里面调用了UseCase的run(),而UseCase的run()最终调用了UseCase的executeUseCase()。通过刚刚的分析,我们应该知道,我们实际上操作的实体应该是UseCase的实现类,而不是UseCase类本身,那么这中间是通过什么方式将对UseCase的操作转移到UseCase的实现类上面的呢?我们会发现UseCaseHandler的execute()传入了UseCase对象作为参数,好的,那么我们就看看execute()是在哪里被调用的吧!

  经过追踪,我们看到在TasksPresenter类中调用了此方法,调用处的代码如下:

 1 @Override
2 public void activateTask(@NonNull Task activeTask) {
3 checkNotNull(activeTask, "activeTask cannot be null!");
4 mUseCaseHandler.execute(mActivateTask, new ActivateTask.RequestValues(activeTask.getId()),
5 new UseCase.UseCaseCallback<ActivateTask.ResponseValue>() {
6 @Override
7 public void onSuccess(ActivateTask.ResponseValue response) {
8 mTasksView.showTaskMarkedActive();
9 loadTasks(false, false);
10 }
11
12 @Override
13 public void onError() {
14 mTasksView.showLoadingTasksError();
15 }
16 });
17 }

  可以看到,我们传入的参数实际上是UseCase的实现类ActivateTask的对象,到这里,我们就明白啦!原来也是子类实例化父类的方式。

  上面我只是简单粗略地讲述了一下项目中部分模块的代码,仅仅是举个例子,更多的东西需要大家自己用面向对象的思想去理解。我说这些的目的就是想告诉大家,充分运面向对象的思想就可以设计出很多看似复杂的架构和项目,但是不管再怎么复杂的代码也肯定是有迹可循的,我们只要抓住了这些设计思想的本质,多看几遍代码,一定会豁然开朗!

Goodle Clean设计架构的更多相关文章

  1. 一张图看Goodle Clean设计架构

    之前用一张图分析了Google给出的MVP架构,但是在Google给出的所有案例里面除了基本的MVP架构还有其它几种架构,今天就来分析其中的Clean架构.同样的,网上介绍Clean架构的文章很多,我 ...

  2. Android App的设计架构:MVC,MVP,MVVM与架构经验谈

    相关:http://www.cnblogs.com/wytiger/p/5996876.html 和MVC框架模式一样,Model模型处理数据代码不变在Android的App开发中,很多人经常会头疼于 ...

  3. Kubernetes系列02—Kubernetes设计架构和设计理念

    本文收录在容器技术学习系列文章总目录 1.Kubernetes设计架构 Kubernetes集群包含有节点代理kubelet和Master组件(APIs, scheduler, etc),一切都基于分 ...

  4. 13 JSP、MVC开发模式、EL表达式和JSPL标签+软件设计架构---学习笔记

    1.JSP (1)JSP概念:Java Server Pages 即java服务器端页面可以理解为:一个特殊的页面,其中既可以指定定义html标签,又可以定义java代码用于简化书写!!! (2)原理 ...

  5. (转)Kubernetes设计架构

    转:https://www.kubernetes.org.cn/kubernetes设计架构 Kubernetes集群包含有节点代理kubelet和Master组件(APIs, scheduler, ...

  6. Android App的设计架构:MVC,MVP,MVVM与架构AAAAA

    1. 架构设计的目的1.1 通过设计使程序模块化,做到模块内部的高聚合和模块之间的低耦合.1.2 这样做的好处是使得程序在开发的过程中,开发人员只需要专注于一点,提高程序开发的效率,并且更容易进行后续 ...

  7. MVC:开发模式&&三层架构:软件设计架构

    MVC:开发模式 jsp演变历史 早期只有servlet,只能使用response输出标签数据,非常麻烦 后来又jsp,简化了Servlet的开发,如果过度使用jsp,在jsp中即写大量的java代码 ...

  8. 解决Tomcat10.0.12源码编译问题进而剖析其优秀分层设计架构

    概述 Tomcat.Jetty.Undertow这几个都是非常有名实现Servlet规范的应用服务器,Tomcat本身也是业界上非常优秀的中间件,简单可将Tomcat看成是一个Http服务器+Serv ...

  9. 微信、陌陌等著名IM软件设计架构详解

    对微信.陌陌等进行了分析,发出来分享一下(时间有些久了) 电量:对于移动设备最大的瓶颈就是电量了.因为用户不可能随时携带电源,充电宝.所以必须考虑到电量问题.那就要检查我们工程是不是有后台运行,心跳包 ...

随机推荐

  1. r语言之生成规则序列,规则序列函数及用法

    在生成序列时,“:”的优先级最高 (1)从1到20的整数序列: > 1:20 [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 (2) ...

  2. 深入浅出—JAVA(3)

    3.认识变量 变量有两种:primitive主数据类型和引用. 变量有两种口味:清凉的primitive主数据类型与香辣的对象引用.primitive主数据类型用来保存基本类型的值,包括整数.布尔和浮 ...

  3. poj 2363 Blocks(暴力)

    题目链接:http://poj.org/problem?id=2363 思路分析:由于数据较小,采用暴力搜索法.假设对于矩形边长 1 <= a <= b <= c <= N; ...

  4. cocos2d-x3.6 连连看连通画线

    我的博客:http://blog.csdn.net/dawn_moon 网上看到非常多人写的连连看,都没有画连线的实现.事实上要话连线挺简单的.cocos2d-x 提供了一个非常方便的绘图形的类.Dr ...

  5. 关于jave在oracle驱动下事务提交与回滚问题

    一直以来,都觉得Connection假设设置了setAutoCommit(false)后.启动手工事务提交.必须手工进行commit或者rollback才行.今天正好遇到一个问题.结果大跌眼镜. 于是 ...

  6. html里面自定义弹出窗口

    网页上默认的提示框或对话框一般比较丑,可以利用div遮盖层来自定义对话框 1.定义一个按钮或者链接(项目里面是通过点击一个图片) <img src="images/zz.gif&quo ...

  7. Xcode使用source control 时提示the server certificate failed to verify 的解决办法

    wusipingdeMacBook-Pro:~ railgun$ wusipingdeMacBook-Pro:~ railgun$ svn ls https://13.13.13.134:8443/s ...

  8. BZOJ 3713: [PA2014]Iloczyn( 枚举 )

    斐波那契数列<10^9的数很少很少...所以直接暴力枚举就行了... ------------------------------------------------------------- ...

  9. java.lang.NoClassDefFoundError: org.ksoap2.transport.HttpTransportSE异常处理

    原因就是没有打包进去  因为引用进去 编译时没出出现问题 解决如下

  10. 为什么使用LUT比GAL 节省资源

    为什么使用LUT比GAL 节省资源 A[1:0]    B[1:0]     实现一个比较器,如果A=B输出1 否则输出0 传统的GAL 需要 24= 16个存储单元(ROM)来存储结果数据,实现方法 ...