一 、需求场景


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

二、分析需求

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

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

梳理元素之间的关系

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

三、代码设计

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. swift 跳转网页写法
  2. Java LinkedList类基本用法
  3. 一个演示A星相关的寻路的网站
  4. js php 数据类型判断,【js基础】变量类型判断
  5. 解决centos使用nc命令报错:Ncat: Connection refused.
  6. ssh相互访问不用密码
  7. NLTK(自然语言工具包)
  8. 运筹说 第4期|掌握运筹学软件,走遍天下都不怕
  9. AutoCAD2012官方原版软件下载
  10. 通过yum安装Oracle instant client
  11. AD画PCB板子 基本步骤
  12. 苹果奖学金获得者:我的自学 iOS 开发历程
  13. Python字符串杂谈
  14. 手机银行业务应用中的关键技术
  15. 多个搜索引擎搜索网站,提高搜索效率,快人一步
  16. 企业微信公众号运营引流的三大法宝
  17. 《我不是药神》——生如夏花
  18. 编码员,程序员,黑客,开发人员和计算机科学家走进维恩图
  19. 【计算机网络系列】网络概述与体系结构
  20. DPLL 算法(求解k-SAT问题)详解(C++实现)

热门文章

  1. 如何选择软考中级科目
  2. 鸿蒙系统手机开机,华为鸿蒙手机开机界面曝光!谷歌安卓被正式取代:打响全球OS争夺战...
  3. vscode 安装sass
  4. Oracle 18c 新特性之CDB航母
  5. 在线学习PS设计精讲精练记录(1)
  6. linux怎么查看tomcat错误日志,Linux下查看Tomcat运行日志
  7. down mark 打钩_markdown文档撰写技巧
  8. update 关联两个表
  9. GB2312 (Simplified Chinese) character code table
  10. 云原生数据库的幕后英雄:浅谈分布式数据库的计算和存储分离