一 、需求场景


需要实现一个分页组件, 可以方便的进行分页操作。

二、分析需求

从分页需求出发,分析潜在的元素, 虽然只包含一个大的分页功能,但是潜在的元素
包含:上一页 下一页 首页 尾页 当前页 等等。

为什么包含这些元素 ?==> 理解业务的能力

梳理元素之间的关系

上一页 == 当前页左移
下一页 == 当前页右移
首页 == 当前页左移到第一个
尾页 == 当前页右移动到最后一个
切换页码== 重新建立一个上一页、下一页、首页、尾页、当前页之间的关系逻辑

三、代码设计

1. 使用MVC模式梳理

为什么选择MVC模式
为什么不上来就干 (基本的从上至下,从左至右的标准规则)
可不可以选择其他设计模式

1.1 MVC简介

MVC是三个单词的首字母缩写,它们是Model(模型)、View(视图)和Controller(控制)。

1.2 分析和创建模型

抽象模型是最难的事在于:

  1. 命名
    这个类要不要作为基类,使用场景多不多,起什么样的名字更贴合意义呢?
  2. 属性建立
    在这个业务场景中的属性够不够,增加属性会不会打破属性间的逻辑关系。

2 建立分页model

基于需求中的元素,建立模型

  • setCurrentPage 公共的可以改变模型中属性的方法
    第一个参数改变当前页的大小,第二个参数改变每页的大小 ,随着当前页和每页大小的改变,随之触发上一页 、下一页、首页、尾页的变化
import lombok.Getter;
import lombok.ToString;import java.io.Serializable;/*** 分页对象类*/
@Getter
@ToString
public class Pager implements Serializable {private static final long serialVersionUID = 4542617637761955078L;/*** 当前页*/private int currentPage;/*** 每页大小*/private int pageSize;/*** 总页数*/private int pageTotal;/*** 总条数*/private int totalCount;/*** 前一页*/private int prevPage;/*** 下一页*/private int nextPage;/*** 第一页*/private int firstPage;/*** 最后一页*/private int lastPage;public Pager(int totalCount) {this(totalCount, 1, 10);}public Pager(int totalCount, int currentPage, int pageSize) {this.totalCount = totalCount;this.firstPage = 1;this.setCurrentPage(currentPage, pageSize);}public void setCurrentPage(int currentPage) {this.setCurrentPage(currentPage, this.pageSize);}/*** 设置当前页** @param currentPage 当前页* @param pageSize    每页数量*/public void setCurrentPage(int currentPage, int pageSize) {this.currentPage = currentPage;if (this.pageSize != pageSize) {this.pageSize = pageSize;this.pageTotal = this.totalCount % this.pageSize > 0 ? this.totalCount / this.pageSize + 1 : this.totalCount / this.pageSize;this.lastPage = this.pageTotal;}if (this.currentPage > this.pageTotal) {this.currentPage = this.pageTotal;}if (currentPage > 1) {this.prevPage = this.currentPage - 1;} else {this.prevPage = this.firstPage;}if (this.currentPage < this.lastPage) {this.nextPage = this.currentPage + 1;} else {this.nextPage = this.lastPage;}}}

3. 建立view和control

视图层:
包含了元素的布局、样式 和基本的动作事件及约束
控制层:
包含了 view和视图之间的逻辑关系, 所以最核心的方法currentPageChange
随着当前页和分页大小的变化,控制model和view的变化

3.1 控制view

所有的view的元素事件都与该方法绑定,根据model的变化,更改view中上一页、下一页 、首页、尾页最大页等元素的状态变化

3.2 控制model

将currentPage当前页和pageSize分页大小的变化传递给model,自动控制上一页、下一页、尾页和首页的属性变化

private void currentPageChange(int currentPage, int pageSize) {pager.setCurrentPage(currentPage, pageSize);limitNumberDocument.setMax(pager.getLastPage());totalPage.setText("/" + pager.getPageTotal());jump.setText(pager.getCurrentPage() + "");if (currentPage <= pager.getFirstPage()) {first.setEnabled(false);prev.setEnabled(false);next.setEnabled(true);last.setEnabled(true);} else if (currentPage >= pager.getLastPage()) {first.setEnabled(true);prev.setEnabled(true);next.setEnabled(false);last.setEnabled(false);} else {first.setEnabled(true);prev.setEnabled(true);next.setEnabled(true);last.setEnabled(true);}}

3.3 完整示例

import cn.hutool.core.util.StrUtil;
import cn.note.swing.core.document.LimitNumberDocument;
import cn.note.swing.core.event.ConsumerAction;
import cn.note.swing.core.event.key.KeyActionFactory;
import cn.note.swing.core.util.FrameUtil;
import cn.note.swing.core.view.AbstractMigView;
import cn.note.swing.core.view.base.SelectedComboBox;
import cn.note.swing.core.view.form.SelectedItem;
import cn.note.swing.core.view.theme.ThemeFlatLaf;
import net.miginfocom.swing.MigLayout;import javax.swing.*;/*** 分页测试*/
public class PaginationTest extends AbstractMigView {/* 分页模型*/private Pager pager;/* 第一页*/private JButton first;/*上一页*/private JButton prev;/* 下一页*/private JButton next;/* 最大页数 */private JButton last;/* 总页数 */private JLabel totalPage;/* 回车跳转*/private JTextField jump;/* 下拉选择*/private SelectedComboBox selectItems;/* 最大数限制*/private LimitNumberDocument limitNumberDocument;@Overrideprotected MigLayout defineMigLayout() {return new MigLayout("");}@Overrideprotected void render() {pager = new Pager(100);first = new JButton("《");prev = new JButton("<");next = new JButton(">");last = new JButton("》");totalPage = new JLabel("/" + pager.getPageTotal());jump = new JTextField();// 限制最大输入页数limitNumberDocument = new LimitNumberDocument(pager.getLastPage());jump.setDocument(limitNumberDocument);// 条数selectItems = new SelectedComboBox();selectItems.addSelectItem(new SelectedItem("10", "10 条/页"));selectItems.addSelectItem(new SelectedItem("20", "20 条/页"));selectItems.addSelectItem(new SelectedItem("30", "30 条/页"));selectItems.addSelectItem(new SelectedItem("40", "40 条/页"));selectItems.addSelectItem(new SelectedItem("50", "50 条/页"));view.add(first);view.add(prev);view.add(jump);view.add(totalPage);view.add(next);view.add(last);view.add(selectItems);handleActions();currentPageChange(1, 10);}/*** 拦截所有动作*/private void handleActions() {// 第一页 上一页 下一页 最后一页first.addActionListener(e -> currentPageChange(pager.getFirstPage()));prev.addActionListener(e -> currentPageChange(pager.getPrevPage()));next.addActionListener(e -> currentPageChange(pager.getNextPage()));last.addActionListener(e -> currentPageChange(pager.getLastPage()));// 回车限制输入不合法时,重置为1KeyActionFactory.bindEnterAction(jump, new ConsumerAction(e -> {String text = jump.getText();if (StrUtil.isBlank(text) || Integer.valueOf(text) == 0) {jump.setText(String.valueOf(pager.getFirstPage()));}currentPageChange(Integer.valueOf(jump.getText()));}));// 变换条数selectItems.onSelected(item -> {currentPageChange(pager.getCurrentPage(), Integer.valueOf(item.getKey()));});}/*** 当前页变化** @param currentPage 当前页*/private void currentPageChange(int currentPage) {currentPageChange(currentPage, pager.getPageSize());}/*** 当前页变化事件** @param currentPage 当前页* @param pageSize    分页大小*/private void currentPageChange(int currentPage, int pageSize) {pager.setCurrentPage(currentPage, pageSize);limitNumberDocument.setMax(pager.getLastPage());totalPage.setText("/" + pager.getPageTotal());jump.setText(pager.getCurrentPage() + "");if (currentPage <= pager.getFirstPage()) {first.setEnabled(false);prev.setEnabled(false);next.setEnabled(true);last.setEnabled(true);} else if (currentPage >= pager.getLastPage()) {first.setEnabled(true);prev.setEnabled(true);next.setEnabled(false);last.setEnabled(false);} else {first.setEnabled(true);prev.setEnabled(true);next.setEnabled(true);last.setEnabled(true);}}public static void main(String[] args) {ThemeFlatLaf.install();FrameUtil.launchTime(PaginationTest.class);}
}

4. 包装为组件及 美化

4.1 使用图标及样式代码进行美化

4.2 使用抽象进行组件封装加入与外部交互

  1. 添加Consumer 进行pager变换的传递

    2. 在currentChange中 触发该方法

5. 实战与表格分页

当你的表格需要分页时, 那么你就可以把你包装的分页组件加进来

  • 代码是轻松维护的, 表格逻辑和分页逻辑无关
  • 代码是可扩展的, 改变分页的风格不会影响表格代码, 因为表格只绑定了分页的model

MVC的设计模式, 没有增加代码量 , 但是让代码具备低耦合和高扩展的特性


四、 语言的互通

1. MVC 在JavaScript中适配

将上述场景,使用MVC还原在h5中

使用类构建js代码容易维护吗?

2. 完整示例

<html>
<body><div><button id="first">《</button><button id="prev">◁</button><!-- 限制只能输入数字 --><input type="text" id="jump" onkeyup="this.value=this.value.replace(/[^\d]/g,'') "onafterpaste="this.value=this.value.replace(/[^\d]/g,'') "><label id="totalPage"></label><button id="next">▷</button><button id="last">》</button><select id="pageSizeSelect"><option value="10">10 条/页</option><option value="20">20 条/页</option><option value="30">30 条/页</option><option value="40">40 条/页</option><option value="50">50 条/页</option></select></div>
</body>
<script>class Pager {/*当前页*/currentPage;/*每页大小*/pageSize;/*总页数*/totalPage;/*总条数*/totalCount;/*前一页*/prevPage;/*下一页*/nextPage;/*第一页*/firstPage;/*最后一页*/lastPage;constructor(totalCount, currentPage = 1, pageSize = 10) {this.totalCount = totalCount;this.firstPage = 1;this.setCurrentPage(currentPage, pageSize);}/*** 设置当前页** @param currentPage 当前页* @param pageSize    每页数量*/setCurrentPage(currentPage, pageSize) {this.currentPage = Number(currentPage);if (this.pageSize != pageSize) {this.pageSize = pageSize;this.totalPage = this.totalCount % this.pageSize > 0 ? Math.floor(this.totalCount / this.pageSize) + 1 : Math.floor(this.totalCount / this.pageSize);this.lastPage = this.totalPage;}if (this.currentPage > this.totalPage) {this.currentPage = this.totalPage;}if (this.currentPage > 1) {this.prevPage = this.currentPage - 1;} else {this.prevPage = this.firstPage;}if (this.currentPage < this.lastPage) {this.nextPage = this.currentPage + 1;} else {this.nextPage = this.lastPage;}}}class PaginationTest {/* 分页模型*/pager;/* 第一页*/first;/*上一页*/prev;/* 下一页*/next;/* 最大页数 */last;/* 总页数 */totalPage;/* 回车跳转*/jump;/* 下拉选择*/pageSizeSelect;constructor(totalCount) {this.pager = new Pager(totalCount);this.first = document.getElementById("first");this.prev = document.getElementById("prev");this.next = document.getElementById("next");this.last = document.getElementById("last");this.totalPage = document.getElementById("totalPage");this.jump = document.getElementById("jump");this.pageSizeSelect = document.getElementById("pageSizeSelect");this.handleActions();this.currentPageChange(1, 10);}/*** 拦截所有动作*/handleActions() {this.first.onclick = () => { this.currentPageChange(this.pager.firstPage, this.pager.pageSize) }this.prev.onclick = () => { this.currentPageChange(this.pager.prevPage, this.pager.pageSize) }this.next.onclick = () => { this.currentPageChange(this.pager.nextPage, this.pager.pageSize) }this.last.onclick = () => { this.currentPageChange(this.pager.lastPage, this.pager.pageSize) }this.pageSizeSelect.onchange = (e) => {this.currentPageChange(this.pager.currentPage, e.target.value)if (this.jump.value > this.pager.totalPage) {this.jump.value = this.pager.totalPage}}// 限制最大输入this.jump.oninput = () => {let v = this.jump.value;if (v > this.pager.totalPage) {this.jump.value = this.pager.totalPage}}this.jump.onchange = () => {let v = this.jump.value;if (!v) {this.jump.value = 1;}this.currentPageChange(this.jump.value, this.pager.pageSize)}}/*** 当前页变化事件** @param currentPage 当前页* @param pageSize    分页大小*/currentPageChange(currentPage, pageSize = 10) {this.pager.setCurrentPage(currentPage, pageSize);this.jump.value = currentPage;this.totalPage.innerHTML = "/" + this.pager.totalPage;if (currentPage <= this.pager.firstPage) {this.first.disabled = true;this.prev.disabled = true;this.next.disabled = false;this.last.disabled = false;} else if (currentPage >= this.pager.lastPage) {this.first.disabled = false;this.prev.disabled = false;this.next.disabled = true;this.last.disabled = true;} else {this.first.disabled = false;this.prev.disabled = false;this.next.disabled = false;this.last.disabled = false;}}}new PaginationTest(100);
</script>
</html>

五、后话

  • 要不要建立模型 ,你给抽通用模型的时间了,催催催?
  • 抽象完的代码能坚持多久,这项目不知道哪天就黄了,还有复用的可能 ?
  • 封装为组件时,控制层需要释放哪些属性 ,那些user天天要我改组件怎么办?
  • 业务代码和非业务代码 使用不使用MVC模式的重点在于,需求变化的可控性 (至上)和程序员的一点骄傲(唯心)

以分页场景谈MVC设计模式相关推荐

  1. 用 Hasor 谈一谈MVC设计模式

    为什么80%的码农都做不了架构师?>>>    MVC 是一个老生常谈的东西早已不是什么稀罕物件,不过在这里还是扒一扒到底都有多少种 MVC. 一.经典 MVC 先说最经典的 MVC ...

  2. 浅谈MVC设计模式和SSH框架的关系

    一.MVC:是指Model-View-Controler,是程序的一种分层模式,是一种思想. MVC是Model-View-Controler的简称.即模型-视图-控制器.MVC是一种设计模式,它强制 ...

  3. 浅谈javaweb三大框架和MVC设计模式

    浅谈javaweb三大框架和MVC设计模式 转载自:http://blog.csdn.net/sunpeng19960715/article/details/50890705 小序:博主以前在学jav ...

  4. mvc设计模式现在过时了吗_尚学堂115——设计模式、源码分析以及SpringData

    设计模式 什么是设计模式?你是否在你的代码里面使用过任何设计模式? 设计模式是在软件设计中常见问题的通用.可反复使用.多数人知晓的一种解决方案或模板:这些解决方案是在相当长的一段时间内由众多软件开发人 ...

  5. 分页场景(limit,offset)为什么会慢?

    点击关注公众号,Java干货及时送达 来源 | juejin.im/post/5c4db295e51d4503834d9c43 从一个问题说起 五年前在tx的时候,发现分页场景下,mysql请求速度非 ...

  6. 第80节:Java中的MVC设计模式

    第80节:Java中的MVC设计模式 前言 了解java中的mvc模式.复习以及回顾! 事务,设置自动连接提交关闭. setAutoCommit(false); conn.commit(); conn ...

  7. Java设计模式(十四):MVC设计模式

    1. 应用场景 MVC设计模式广泛应用于桌面应用程序开发和网页页面开发这些与用户交互的应用场景中. 2.概念 众所周知MVC不是设计模式,是一个比设计模式更大一点的模式,称作设计模式不合理,应该说MV ...

  8. Java——Web开发之MVC设计模式的学生信息管理系统(二)

    为什么这个标题为"(二)",其实是对于上一个特别简单学生信息管理系统里功能的完善. 所谓的"(一)"在这:学生信息管理系统(一) 系统实现的功能: 实现添加学生 ...

  9. 浅谈 MVC、MVP 和 MVVM 架构模式

    2019独角兽企业重金招聘Python工程师标准>>> 谈谈 MVX 中的 Model 谈谈 MVX 中的 View 谈谈 MVX 中的 Controller 浅谈 MVC.MVP ...

最新文章

  1. 自动驾驶资料合集:视频、书籍与开源项目
  2. OpenAI逆炼以文生图:参数缩水2/3性能却更强,还get局部编辑新技能|可试玩
  3. Linux20180416四周第一次课(4月11日)
  4. datagridview当传递具有已修改行的 DataRow 集合时,更新要求有效的 UpdateCommand。
  5. Theano深度学习入门
  6. 1035. 插入与归并(25)
  7. python合并列表并按升序排序_在python中按升序合并两个排序的链接列表:单链接列表指针更新问题...
  8. Billboard HDU - 2795(树状数组,单点修改,区间查询)
  9. python接口自动化(四十四)- 公共模块configparser读取ini数据库、邮箱配置文件(单独说明)
  10. iOS开发之实现方法链调用
  11. tcp云服务器连接,云服务器可以tcp通讯吗
  12. 大哥吾博文写得清清楚楚,怎么就不试一下?
  13. c语言判断算符优先级,C语言算符优先级(精华)
  14. 联想计算机怎么设置硬盘,联想电脑硬盘模式怎么更改
  15. 如何在Coldfusion中上传文件
  16. 三极管PNP NPN 的判别
  17. 为什么要学数学--读《给讨厌数学的人》第二章之读书笔记
  18. 架构的道与术-软件架构设计
  19. 全网疯传,阿里 P8 技术官的架构笔记外泄:微服务分布式架构实践手册
  20. easyexcel获取所有sheet页名称_【EXCEL】如何快速获取所有表格名称

热门文章

  1. Python协程讲解
  2. PR如何把视频拉满整个屏幕
  3. windows中redis 清除缓存
  4. html52倍行间距怎么设置,word怎么设置2倍行距
  5. java采集腾讯动漫
  6. 【ps】如何使用photo shop改变指定区域颜色
  7. proteus与keil的安装方法合集
  8. window server 2012 r2 安装卸载sqlserver 2012
  9. Flash Loader Demonstrator v2.8.0下载
  10. Java基础--语法概念,练习数字金字塔