尽可能的构建一个拓展性比"较好"的项目,会让你后期迭代好受点
转载请注明出处:王亟亟的大牛之路
这礼拜基本都在忙自己项目上的事,然后之后会“重新整理”后把这部分的功能开源出来,这里@下队友 NeglectedByBoss
本周还是没有停更收纳库,继续安利:https://github.com/ddwhan0123/Useful-Open-Source-Android (把疑难杂症给拆出去了,还剩资料,工具类和自定义控件的细分工作)
这一篇来简单的模拟一个读书的业务流程来谈一下代码拓展性的问题
建立模型
首先我们得 建立书的对象
public class Book<T> {
public String Name; //书名
public int PageCount; //总页数
public int NowPage; //当前页数
public T BookMoreMSG; //附加信息
/**
* get set等其他方法省略
*/
因为我们读一本书 肯定有他的一些基本信息,这里就 设置了书名,总页数,当然还可以有作者,出版日期等等等,我们只是例子不需要太复杂
NowPage 用来判断读书进展
BookMoreMSG 这是个泛型,也就是我们的补充项,让每一本书的对象更鲜活。而让代码实现也更灵活,增强了我们的拓展性,他可以是一句话 ,可以是一个对象 等等等。
读书状态回调
写的时候其实我没有刻意的要想怎么去假设,怎么去设计也就是写着写着改着改着(这种方式本身不太好,还是建议大家在开始敲代码之前好好的想想怎么做更好)
那既然读书,肯定是要慢条斯理的,而且还肯定要有状态于是我就让这个读书的行为用一个子线程然后让他 .Sleep()下来模拟正在读书的行为
先创建一个读书状态无非是 开始读书,正在读书,读完了 那么我们就用一个接口去实现
public interface ReadListener<T> {
//开始读书
void start();
//正在读书
void doing(T t);
//读完了
void finish(T t);
}
因为我们书有一系列的属性,所以我们把书的状态作为参数传入,又因为这个接口(可能)可以在别的地方复用 所以传入的参数还是用了泛型
填充数据
读书之前我们得有书,所以我们得填充下数据,这本奥特曼打怪兽 我们给他一个描述语句 是神秘的反派角色 ,他总共 15页,我们的小宝宝从头开始读
/*
* 模拟数据
* */
private Book<String> addBook() {
book = new Book<>();
book.setBookMoreMSG("神秘的反派角色");
book.setName("奥特曼打怪兽");
book.setPageCount(15);
book.setNowPage(0);
return book;
}
读书的实现
读书的状态跟视图(也就是Activity/Fragment)没什么关系,所以为了让视图 更 视图 让一个类在子线程去读书吧,如果想在页面上展示进度直接用接口传递就好了,So Easy!!
那我们再写个接口,让他作为传播媒介告诉UI好了
public interface CommunicateListener {
void setMsg(Message msg);
}
非常简单的一个接口,传递一个Message对象,你想给UI传啥都行了。
既然要实现读书,那肯定要实现读书状态的回调,那我们就来实现他
因为上面确定了,我们图书的附加内容是一句话,那泛型的书就都成了Book<String>
类型的Book了
public class ReadImp implements ReadListener<Book<String>> {
Book<String> book;
CommunicateListener communicate;
public void setMessager(CommunicateListener communicate) {
this.communicate = communicate;
}
public ReadImp(Book<String> book) {
this.book = book;
}
@Override
public void start() {
Log.d("--->", "ReadImp 开始读书");
}
@Override
public void doing(Book<String> book) {
Log.d("--->", "现在读到第 " + book.getNowPage() + "页");
}
@Override
public void finish(Book<String> book) {
Log.d("--->", "读完了,总共读了 " + book.getNowPage() + "页");
Message message = Message.obtain();
message.obj = book.getBookMoreMSG();
communicate.setMsg(message);
}
}
这里没有让消息一直刷UI就 读书读完了 让他 把他读完的消息发出去。
逻辑实现算是通了,那我们来看下UI咯
主UI
下面还有个TextView,因为一开始宝宝没有读完书,所以没字。
public class MainActivity extends AppCompatActivity implements View.OnClickListener, CommunicateListener {
private Button read_btn, send_text;
private ReadImp readImp;
private EditText edit_baobao;
private ReadThread readThread;
private Thread thread;
private volatile Book<String> book;
private ReadBookTextView read_text;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init() {
Log.d("--->", "主线程的 ID 是 " + Thread.currentThread().getId());
//给书赋值
addBook();
readImp = new ReadImp(book);
readImp.setMessager(this);
readThread = new ReadThread(book, readImp);
thread = new Thread(readThread);
initWidget();
}
@Override
protected void onStart() {
super.onStart();
thread.start();
Log.d("--->", "开启的线程 ID 是 " + thread.getId());
}
@Override
protected void onStop() {
super.onStop();
thread.interrupt();
}
@Override
protected void onDestroy() {
super.onDestroy();
thread = null;
readThread = null;
}
private void initWidget() {
read_text = (ReadBookTextView) findViewById(R.id.read_text);
read_btn = (Button) findViewById(R.id.read_btn);
send_text = (Button) findViewById(R.id.send_text);
edit_baobao = (EditText) findViewById(R.id.edit_baobao);
send_text.setOnClickListener(this);
read_btn.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.read_btn:
read_text.setText("");
thread.interrupt();
break;
case R.id.send_text:
if (edit_baobao.getText().toString().trim().length() > 0) {
read_text.setText(edit_baobao.getText().toString().trim());
}
break;
}
}
@Override
public void setMsg(Message msg) {
read_text.setText("补充内容是 " + msg.obj.toString());
}
/*
* 模拟数据
* */
private Book<String> addBook() {
book = new Book<>();
book.setBookMoreMSG("神秘的反派角色");
book.setName("奥特曼打怪兽");
book.setPageCount(15);
book.setNowPage(0);
return book;
}
}
我们的MainActivity 实现了 看消息的 CommunicateListener接口
所以在实现类读完了书会告诉我们他要告诉我们的Message
补充下 ReadBookTextView这个类是我零时改的一个 自定义TextView,可以在子线程修改,之前的博客介绍过,直接COPY过来改了改
传送门:http://blog.csdn.net/ddwhan0123/article/details/50956307
也就是说我们读书的过程都是在子线程读的,我们读完书的结果也是在子线程刷新的UI。
OK,那整个DEMO要阐明什么?
共有的一些逻辑/概念/行为,可以抽象的一定要抽象,好处在于 1省代码,2维护性好,3拓展性强。(这本书无论换什么类型的描述字段我们都可以用一套代码来实现,最多加不同的IMP实现,当然你可以在IMP实现上再加一层封装,那更SO EASY了!)
频繁的刷UI本身就是对MainThread进行“摧残”,但是有些时候我们还真没办法,那简单的一些刷UI的工作就可以放到子线程里去做,诸如各种setText,set…set…等等等,当然这个还是要取决于 “团队可用于子线程刷新的组件的厚度”,反正是能往子线程丢就丢。(Rx套餐其实是把非UI的行为全挪走了,我们这里的做法就是能分担多少就分担多少,充分利用现在手机多CPU的特性)
项目结构,其实也不用盲目的 MVC MVP MVVP什么的,适合自己项目实际场景的才是最好的(虽然我不知道怎么的写着写着这个例子有点MVP的味道)
多利用OOP的特性
补一些过程中的图吧
读书的过程
项目结构
当然这篇完全是我随手写出来的,真是想到哪写到哪,最后写完了才发现 嘿?好像可以来篇Blog什么的解释下,如果有不对的地方请大家指出(肯定有很多不足的地方,但是思路大家可以参考下)。
(其实最初是想写关于Number的,哈哈哈)
git地址:https://github.com/ddwhan0123/BlogSample/tree/master/NumberDemo
附件下载地址:https://github.com/ddwhan0123/BlogSample/blob/master/NumberDemo/NumberDemo.zip?raw=true
尽可能的构建一个拓展性比"较好"的项目,会让你后期迭代好受点的更多相关文章
- springboot:快速构建一个springboot项目
前言: springboot作为springcloud的基础,springboot的热度一直很高,所以就有了这个springboot系列,花些时间来了解和学习为自己做技术储备,以备不时之需[手动滑稽] ...
- .Net中的AOP系列之构建一个汽车租赁应用
返回<.Net中的AOP>系列学习总目录 本篇目录 开始一个新项目 没有AOP的生活 变更的代价 使用AOP重构 本系列的源码本人已托管于Coding上:点击查看. 本系列的实验环境:VS ...
- 《Entity Framework 6 Recipes》中文翻译系列 (20) -----第四章 ASP.NET MVC中使用实体框架之在MVC中构建一个CRUD示例
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第四章 ASP.NET MVC中使用实体框架 ASP.NET是一个免费的Web框架 ...
- 如何用 Swift 语言构建一个自定控件
(via:破船之家,原文:How To Make a Custom Control in Swift) 用户界面控件是所有应用程序重要的组成部分之一.它们以图形组件的方式呈现给用户,用户可以通过它 ...
- Android TV开发总结(六)构建一个TV app的直播节目实例
请尊重分享成果,转载请注明出处:http://blog.csdn.net/hejjunlin/article/details/52966319 近年来,Android TV的迅速发展,传统的有线电视受 ...
- 快速构建一个 Springboot
快速构建一个 Springboot 官网:http://projects.spring.io/spring-boot/ Spring Boot可以轻松创建可以“运行”的独立的,生产级的基于Spring ...
- 构建一个简单的Spring Boot项目
11 构建一个简单的Spring Boot项目 这个章节描述如何通过Spring Boot构建一个"Hello Word"web应用,侧重介绍Spring Boot的一些重要功能. ...
- 构建一个基本的前端自动化开发环境 —— 基于 Gulp 的前端集成解决方案(四)
通过前面几节的准备工作,对于 npm / node / gulp 应该已经有了基本的认识,本节主要介绍如何构建一个基本的前端自动化开发环境. 下面将逐步构建一个可以自动编译 sass 文件.压缩 ja ...
- .NET Core的文件系统[5]:扩展文件系统构建一个简易版“云盘”
FileProvider构建了一个抽象文件系统,作为它的两个具体实现,PhysicalFileProvider和EmbeddedFileProvider则分别为我们构建了一个物理文件系统和程序集内嵌文 ...
随机推荐
- mysql5.7的密码
[root@mysql ~]# grep "temporary password" /var/log/mysqld.log 2018-04-03T08:08:05.867624Z ...
- 一起学 Java集合框架、数据结构、泛型
一.Java 集合框架 集合框架是一个用来代表和操纵集合的统一架构.所有的集合框架都包含如下内容: 接口:是代表集合的抽象数据类型.接口允许集合独立操纵其代表的细节.在面向对象的语言,接口通常形成一个 ...
- jQuery 对象访问 index([selector|element])
搜索匹配的元素,并返回相应元素的索引值,从0开始计数. 如果不给 .index() 方法传递参数,那么返回值就是这个jQuery对象集合中第一个元素相对于其同辈元素的位置. 如果参数是一组DOM元素或 ...
- 【Redis】redis分页查询理解
偶然在代码中发现一个接口,接口定义说是分页查询,但逻辑实现是Redis.不太理解,Redis怎么分页?后来看到一篇文章,然后了解了. 1.Zrevrange实现 通过SortedSet的zrevran ...
- 【IDEA】单元测试:项目中引入JUnit测试框架+Mock简单了解
一.Junit 使用和说明: 参考:单元测试第三弹--使用JUnit进行单元测试-HollisChuang's Blog http://www.hollischuang.com/archives/17 ...
- BLOCK方式实现OC程序中多个页面判定用户是否登录
在程序中经常会遇到这种情况,用户刚进入我们软件的时候我们是无需要求用户登录的,但是在下面的页面中,例如收藏,购买等页面的时候,显然在多个页面需要多次判定用户是否登录.试着用block简单的实现了一下该 ...
- https://help.aliyun.com/knowledge_detail/49787.html?spm=a2c4g.11186631.2.3.6f856f39tiE98P
https://help.aliyun.com/knowledge_detail/49787.html?spm=a2c4g.11186631.2.3.6f856f39tiE98P
- 查看python对象的属性
在Python语言中,有些库在使用时,在网络上找到的文档不全,这就需要查看相应的Python对象是否包含需要的函数或常量.下面介绍一下,如何查看Python对象中包含哪些属性,如成员函数.变量等,其中 ...
- for...of 与 for...in 区别
一.for...of 1.定义 for...of 语句遍历可迭代对象(包括数组.Set 和 Map 结构.arguments 对象.DOM NodeList 对象.字符串等). 2.语法 for (v ...
- linux里的CPU负载
昨天查看Nagios警报信息,发现其中一台服务器CPU负载过重,机器为CentOS系统.信息如下: 2011-2-15 (星期二) 17:50 WARNING - load average: 9.73 ...