做的美食视频网站,湖北联诺建设网站,外贸企业网站系统,企业微信公众平台导读
Don Roberts提出的一条重构准则#xff1a; 第一次做某件事时只管去做#xff1b;第二次做类似的事时会产生反感#xff0c;但无论如何还是可以去做#xff1b;第三次再做类似的事时#xff0c;你就应该重构。 编码也是如此#xff0c;当多次编写类似的代码时…导读
Don Roberts提出的一条重构准则 第一次做某件事时只管去做第二次做类似的事时会产生反感但无论如何还是可以去做第三次再做类似的事时你就应该重构。 编码也是如此当多次编写类似的代码时我们需要考虑是否有一种方法能够提高编码速度。作者多年来致力于敏捷开发总结了一套编码的方法论有助于程序员快速、优质、高效地进行编码。
方法1手工编写代码
大多数刚学习Java的程序员都会怀着一种崇敬的仪式感一字一句地在开发工具上敲出以下代码
public class Test {public static void main(String[] args) {System.out.println(Hello world!);}
}
没错这就是经典的Hello world这也是大多数人手工编写的第一个程序。
手工编写代码更能体现一个程序员的基本素质。有很多公司都把上机编程考试作为面试的重要手段之一。面试者需要根据题目的要求挑选一款熟悉的编程工具比如Eclipse手工编写代码并调试运行通过。在整个过程中不能通过网络搜索答案不能查看联机帮助文档要求面试者必须手工编写代码主要是考察面试者手工编写代码的能力——语法、函数、逻辑、思维、算法以及动手能力。
手工编写代码是一个优秀程序员必须具备的基础能力。手工编写代码正如提笔写文章语法就是遣词造句的方法、函数就是组成文章的词句、类库就是据经引典的掌故、架构就是行文表述的体裁、功能就是写作文章的主旨、算法就是组织语言的逻辑……所以只要掌握一门程序语言的语法、学习一堆基础类库的函数、引用一些所需的第三方类库、选择一款成熟稳定的架构、明确一下产品需求的功能、挑选一种实现逻辑的算法……手工编写代码就会像写文章一样手到擒来。
方法2复制粘贴代码
常言道熟读唐诗三百首不会作诗也会吟。编码也是同样的道理编码的第一步就是模仿简单地说就是抄代码——复制粘贴代码。复制粘贴代码是一门艺术用好了编码会事半功倍。但是没有检验过的东西终究是不可全信的。当看到需要的代码时在复制粘贴前我们都需要仔细研读、认真思考、详细甄别……很多东西都是仁者见仁、智者见智的东西适合别的场景但不一定适合你的场景。作为一名合格的程序员切不可一味地拿来主义。
1.为什么要复制粘贴代码
复制粘贴现有代码可以节省开发时间复制粘贴稳定代码可以降低系统故障风险复制粘贴网络代码可以把别人的成果化为己用。
2.复制粘贴代码带来问题
你对复制的代码理解程度是多少实现逻辑是否合理能不能稳定运行存在多少潜在的 Bug?这个代码在项目中已经复制粘贴了多少次根据“三则重构”原则你是否需要对这些相同代码进行重构代码被复制粘贴次数越多带来的代码维护问题越多。多个代码版本的更改和修正要保持这些代码的同步就必须需要在每一处进行同样的修改增加了维护的成本和风险。
总之复制粘贴代码跟其它编码方法一样没有优劣对错之分。它只是一种方法你可以善用也可以滥用。如果我们用到了复制粘贴我们就必须为结果负责。
方法3用文本替换生成代码
1.生成代码样例
已经编写好的用户查询相关代码
/** 查询用户服务函数 */
public PageDataUserVO queryUser(QueryUserParameterVO parameter) {Long totalCount userDAO.countByParameter(parameter);ListUserVO userList null;if (Objects.nonNull(totalCount) totalCount.compareTo(0L) 0) {userList userDAO.queryByParameter(parameter);}return new PageData(totalCount, userList);
}/** 查询用户控制器函数 */
RequestMapping(path /queryUser, method RequestMethod.POST)
public ResultPageDataUserVO queryUser(Valid RequestBody QueryUserParameterVO parameter) {PageDataUserVO pageData userService.queryUser(parameter);return Result.success(pageData);
}
如果我们要编写公司查询相关代码其代码形式与用户查询类似整理出替换关系如下
把用户替换为公司;把User替换为Company;把user替换为company。
利用Notepad、EditPlus等文本编辑器选择区分大小写进行普通文本替换最终得到结果如下
/** 查询公司服务函数 */
public PageDataCompanyVO queryCompany(QueryCompanyParameterVO parameter) {Long totalCount companyDAO.countByParameter(parameter);ListCompanyVO companyList null;if (Objects.nonNull(totalCount) totalCount.compareTo(0L) 0) {companyList companyDAO.queryByParameter(parameter);}return new PageData(totalCount, companyList);
}/** 查询公司控制器函数 */
RequestMapping(path /queryCompany, method RequestMethod.POST)
public ResultPageDataCompanyVO queryCompany(Valid RequestBody QueryCompanyParameterVO parameter) {PageDataCompanyVO pageData companyService.queryCompany(parameter);return Result.success(pageData);
}
利用文本替换生成代码整段代码生成时间不会超过1分钟。
2.主要优缺点
主要优点
生成代码速度较快。
主要缺点
必须编写样例代码只适用于文本替换的情景。
方法4用Excel公式生成代码
Excel的公式非常强悍可以用于编写一些公式化的代码。
1.利用Excel公式生成模型类
从WIKI上拷贝接口模型定义到Excel里样例数据内容如下 ABCDEF1序号字段名称字段类型字段描述是否可空附加信息21idLong用户标识否 32nameString用户名称否 43sexInteger用户性别否0:未知;1:男;2:女54descriptionString用户描述是
编写Excel公式如下 /** D6IF(ISBLANK(F6), , (F6)) */ IF(E6 否, IF(C6 String, NotBlank, NotNull), ) private C6 B6;
利用公式生成代码如下
/** 用户标识 */ NotNull private Long id;
/** 用户名称 */ NotBlank private String name;
/** 用户性别(0:未知;1:男;2:女) */ NotNull private Integer sex;
/** 用户描述 */ private String description;
创建模型类整理代码如下
/** 用户DO类 */
public class UserDO {/** 用户标识 */NotNullprivate Long id;/** 用户名称 */NotBlankprivate String name;/** 用户性别(0:未知;1:男;2:女) */NotNullprivate Integer sex;/** 用户描述 */private String description;......
}
2.利用Excel公式生成枚举类
从WIKI上拷贝枚举定义到Excel里样例数据内容如下 ABCD1序号字段取值字段名称字段描述210NONE空321MAN男432WOMAN女
编写Excel公式如下
/** D2(B2) */C2(B2, D2),
利用公式生成代码如下
/** 空(0) */NONE(0, 空),
/** 男(1) */MAN(1, 男),
/** 女(2) */WOMAN(2, 女),
创建枚举类整理代码如下
/** 用户性别枚举 */
public enum UserSex {/** 枚举定义 *//** 空(0) */NONE(0, 空),/** 男(1) */MAN(1, 男),/** 女(2) */WOMAN(2, 女);......
}
3.利用Excel公式生成数据库语句
用Excel整理的公司列表如下需要整理成SQL语句直接插入数据库 ABCDE1序号公司名称公司地址公司电话公司邮箱21高德首开大厦(010)11111111gaodexxx.com32阿里云绿地中心(010)22222222aliyunxxx.com43菜鸟阿里中心(010)33333333cainiaoxxx.com
编写Excel公式如下 (B2, C2, D2, E2),
利用公式生成SQL如下
(高德, 首开大厦, (010)11111111, gaodexxx.com),
(阿里云, 绿地中心, (010)22222222, aliyunxxx.com),
(菜鸟, 阿里中心, (010)33333333, cainiaoxxx.com),
添加into语句头整理SQL如下
insert into t_company(name, address, phone, email) values
(高德, 首开大厦, (010)11111111, gaodexxx.com),
(阿里云, 绿地中心, (010)22222222, aliyunxxx.com),
(菜鸟, 阿里中心, (010)33333333, cainiaoxxx.com);
4.主要优缺点
主要优点
适用于表格化数据的代码生成写好公式后拖拽生成代码生成速度较快。
主要缺点
不适用于复杂功能的代码生成。
方法5用工具生成代码
用工具生成代码顾名思义就是借用已有的工具生成代码。很多开发工具都提供一些工具生成代码比如生成构造函数重载基类/接口函数生成Getter/Setter函数生成toString函数……能够避免很多手敲代码。还有一些生成代码插件也可以生成满足某些应用场景的代码。
这里以mybatis-generator插件生成代码为例介绍如何利用工具生成代码。
1.安装运行插件
具体方法这里不再累述自行上网搜索文档了解。
2.生成代码样例
2.1.生成模型类代码
文件User.java内容
......
public class User {private Long id;private String user;private String password;private Integer age;......
}
2.2.生成映射接口代码
文件UserMapper.java内容
......
public interface UserMapper {User selectByPrimaryKey(Long id);......
}
2.3.生成映射XML代码
文件UserMapper.xml内容
......
mapper namespacecom.test.dao.UserMapper resultMap idBaseResultMap typecom.test.pojo.User id columnid propertyid jdbcTypeBIGINT /result columnuser propertyuser jdbcTypeVARCHAR /result columnpassword propertypassword jdbcTypeVARCHAR /result columnage propertyage jdbcTypeINTEGER //resultMapsql idBase_Column_List id, user, password, age/sqlselect idselectByPrimaryKey resultMapBaseResultMap parameterTypejava.lang.Long select include refidBase_Column_List /from test_userwhere id #{id,jdbcTypeBIGINT}/select......
/mapper
3.主要优缺点
主要优点
利用生成代码插件生成代码速度较快利用插件配置文件控制生成想要的功能代码。
主要缺点
需要时间研究和熟悉生成代码插件的使用生成的代码不一定满足代码规范每次生成后需进行代码合规重新生成代码后容易覆盖自定义代码建议维护单独的生成代码库通过DIFF工具比较代码差异然后再赋值粘贴差异代码。
方法6用代码生成代码
用代码生成代码就是自己编写代码按照自己的格式生成代码。下面以生成基于MyBatis的数据库访问代码为例说明。
1.查询表格信息
首先我们要从数据库中拿到我们生成代码所需要的表和列相关信息。
1.1.查询表信息
查询表信息语句
select t.table_name as 表名称
, t.table_comment as 表备注
from information_schema.tables t
where t.table_schema ?
and t.table_type BASE TABLE
and t.table_name ?;
其中第1个问号赋值数据库名称第2个问号赋值表名称。
查询表信息结果
序号表名称表备注1org_company组织公司表
1.2.查询列信息
查询列信息语句
select c.column_name as 列名称
, c.column_comment as 列备注
, c.data_type as 数据类型
, c.character_maximum_length as 字符长度
, c.numeric_precision as 数字精度
, c.numeric_scale as 数字范围
, c.column_default as
, c.is_nullable as 是否可空
, c.column_key as 列键名
from information_schema.columns c
where c.table_schema ?
and c.table_name ?
order by c.ordinal_position;
其中第1个问号赋值数据库名称第2个问号赋值表名称。
查询列信息结果
序号列名称列备注数据类型字符长度数字精度数字范围是否可空列键名1id公司标识bigint 190NOPRI2name公司名称varchar50 NO 3address联系地址varchar200 YES 4description公司描述text65535 YES
2.编写生成代码
2.1.编写生成模型类代码
/** 生成模型类文件函数 */
private void generateModelClassFile(File dir, Table table, ListColumn columnList) throws Exception {try (PrintWriter writer new PrintWriter(new File(dir, className DO.java))) {String className getClassName(table.getTableName());String classComments getClassComment(table.getTableComment());writer.println(package groupName . systemName .database;);......writer.println(/** classComments DO类 */);writer.println(Getter);writer.println(Setter);writer.println(ToString);writer.println(public class className DO {);for (Column column : columnList) {String fieldType getFieldType(column);String fieldName getFieldName(column.getColumnName());String fieldComment getFieldComment(column);writer.println(\t/** fieldComment */);writer.println(\tprivate fieldType fieldName ;);}writer.println(});}
}
2.2.编写生成DAO接口代码
/** 生成DAO接口文件函数 */
private void generateDaoInterfaceFile(File dir, Table table, ListColumn columnList, ListColumn pkColumnList) throws Exception {try (PrintWriter writer new PrintWriter(new File(dir, className DAO.java))) {String className getClassName(table.getTableName());String classComments getClassComment(table.getTableComment());writer.println(package groupName . systemName .database;);......writer.println(/** classComments DAO接口 */);writer.println(public interface className DAO {);writer.println(\t/** 获取 classComments 函数 */);writer.print(\tpublic className DO get();boolean isFirst true;for (Column pkColumn : pkColumnList) {if (!isFirst) {writer.print(, );} else {isFirst false;}String fieldType getFieldType(pkColumn);String fieldName getFieldName(pkColumn.getColumnName());writer.print(Param(\ fieldName \) fieldType fieldName);}writer.println(););......writer.println(});}
}
2.3.编写生成DAO映射代码
/** 生成DAO映射文件函数 */
private void generateDaoMapperFile(File dir, Table table, ListColumn columnList, ListColumn pkColumnList) throws Exception {try (PrintWriter writer new PrintWriter(new File(dir, className DAO.xml))) {String className getClassName(table.getTableName());String classComments getClassComment(table.getTableComment());writer.println(?xml version\1.0\ encoding\UTF-8\?);......writer.println(!-- classComments 映射 --);writer.println(mapper namespace\ groupName . systemName .database. className DAO\);writer.println(\t!-- 所有字段语句 --);writer.println(\tsql id\fields\);if (CollectionUtils.isNotEmpty(columnList)) {boolean isFirst true;String columnName getColumnName(pkColumn.getColumnName());for (Column column : columnList) {if (isFirst) {isFirst false;writer.println(\t\t columnName);} else {writer.println(\t\t, columnName);}}}writer.println(\t/sql);writer.println(\t!-- 获取 classComments 函数语句 --);writer.println(\tselect id\get\ resultType\ groupName . systemName .database. className DO\);writer.println(\t\tselect);writer.println(\t\tinclude refid\fields\/);writer.println(\t\tfrom table.getTableName());boolean isFirst true;for (Column pkColumn : pkColumnList) {String columnName getColumnName(pkColumn.getColumnName());String fieldName getFieldName(pkColumn.getColumnName());writer.print(\t\t);if (isFirst) {writer.print(where);isFirst false;} else {writer.print(and);}writer.println( columnName #{ fieldName });}writer.println(\t/select);writer.println(/mapper);}
}
3.生成相关代码
3.1.生成的模型类代码
/** 组织公司DO类 */
Getter
Setter
ToString
public class OrgCompanyDO {/** 公司标识 */private Long id;/** 公司名称 */private String name;/** 联系地址 */private String address;/** 公司描述 */private String description;
}
3.2.生成的DAO接口代码
/** 组织公司DAO接口 */
public interface OrgCompanyDAO {/** 获取组织公司函数 */public OrgCompanyDO get(Param(id) Long id);
}
3.3.生成的DAO映射代码
!-- 组织公司映射 --
mapper namespacexxx.database.OrgCompanyDAO!-- 所有字段语句 --sql idfieldsid, name, address, description/sql!-- 获取组织公司函数语句 --select idget resultTypexxx.database.OrgCompanyDOselectinclude refidfields/from org_companywhere id #{id}/select
/mapper
3.主要优缺点
主要优点
代码格式可以定制保证生成代码合规代码功能可以定制只生成需要的代码经过前期代码沉淀后后期能够直接使用。
主要缺点
需要研究数据来源保证能获取到生成代码所需的数据需要建立数据模型、编写生成代码耗费时间比较长。
终极方法无招胜有招
编码的终极方法是不是直接对着电脑说需求然后电脑就自动生成代码了未来科技发展到一定水平后这种情况或许会变成现实。但是目前这种情况是不现实的。现实中想要做到大口一张、代码就来除非你是老板、产品经理或者技术管理者。
编码的终极方法是“无招胜有招”无招并不是不讲究招式而是不拘泥于某一招式信手拈来合适的招式为宜。本文中列举的各种编码方法没有高低优劣之分只有合不合适之说。所以灵活地运用各种编码方法就是编码的终极方法。
代码规范化
在上面的各种编码方法中很多方法都需要手工编写样例代码。如果你的代码不遵循代码规范就很难发现代码之间的共性并抽象出能够作为标准的样例代码如果作为标准的样例代码不满足代码规范必然导致生成的代码也不满足代码规范于是把这些不规范放大了十倍、百倍甚至千倍。 所以代码规范化是编码的重中之重。
请参考阿里集团的开发规约
《阿里经济体开发规约》
我写的一些代码规范化建议
《Java函数优雅之道》
《那些年我们见过的Java服务端“乱象”》
后记
在构思这篇文章的时候在网上看见这么一个梗一位网友讽刺一位阿里人的简历满篇都是沉淀了一套XX方法论为XX业务赋能。用了流行语赋能显得很高大上。姑且不论他的简历如何能够从方法论上着手的人一定有值得我们学习的地方。这里我也来蹭一下这个梗就取一个高大上的名字《编码方法论赋能你我他》。
原文链接 本文为云栖社区原创内容未经允许不得转载。