电子开发 | 基础入门 | 电路原理图 | 梯形图实例 | PLC基础   《如果喜欢本站,请按 Ctrl+D 手动收藏!感谢您的支持》一起学习一起进步,电子开发王欢迎您!.

电子开发网

电子开发网电子设计 | 电子开发网Rss 2.0 会员中心 会员注册

★电路公式手册,最新版《电子电路公式计算器》,电路公式查询手册 电路公式计算器【电子从业人员必备手册】
☆十天学会单片机实例100 c语言 chm格式。资料内容详细,覆盖例子多,内容广【电子从业人员必备手册】
搜索: 您现在的位置: 电子开发网 >> 编程学习 >> Java >> 正文

JAVA开发规范

作者:佚名    文章来源:本站原创    点击数:346    更新时间:2023/10/1

一、编程规范

(一)命名规范:(命名要望文知意,不要嫌长)

  1. 包名要统一小写

  1. 类名、接口名遵从驼峰式命名,DO / BO /DTO / VO / AO/PO例外

例子:MarcoPolo / UserDO / XmlService / TcpUdpDeal

  1. 方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格

例子:localValue / getHttpMessage() / inputUserId

  1. 常量命名全部大写,单词间下划线隔开

例子:MAX_STOCK_COUNT

  1. 枚举类名要以Enum为后缀,且枚举成员名称要全大写,和常量命名一样

例子:枚举类名 ProcessStatusEnum 枚举成员名称 SUCCESS/UNKOWN_REASON

  1. Service/DAO层方法命名:

  1. 获取单个对象的方法用get做前缀

  1. 获取多个对象的方法用list做前缀

  1. 获取统计值的方法用count做前缀

  1. 插入的方法用save/insert做前缀

  1. 删除的方法用remove/delete做前缀

  1. 修改的方法用update做前缀

  1. 领域模型命名

  1. 查询数据库对象:xxxPO

  1. 业务逻辑层对象:xxxBO

  1. 接收客户端参数的对像:xxxVO

  1. 层级之间的数据传输对象:xxxDTO

(二)常量定义

  1. 不允许任何魔法值(即未经定义的常量)直接出现在代码中。常量的复用层次有五层:跨应用共享常量、应用内共享常量、子工程内共享常量、包内共享常量、类内共享常量

  1. 跨应用共享常量:放置在二方库中,通常是client.jar中的constant目录下

  1. 应用内共享常量:放置在一方库中,通常是modules中的constant目录下

  1. 子工程内部共享常量:即在当前子工程的constant目录下

  1. 包内共享常量:即在当前包下单独的constant目录下

  1. 类内共享常量:直接在类内部private static final定义

  1. 如果变量值在一个范围内变化,且带有名称之外的延展属性,定义为枚举类

例子:数字就是延伸信息,标识星期几

public Enum { MONDAY(1), TUESDAY(2), WEDNESDAY(3), THURSDAY(4), FRIDAY(5), SATURDAY(6),SUNDAY(7);}

(三)代码格式

  1. 方法体内的执行语句组、变量的定义语句组、不同的业务逻辑之间或者不同的语义之间插入一个空行。

  1. 单行字符数限制不超过 120 个,超出需要换行,换行时遵循如下原则:

  1. 第二行相对第一行缩进 4 个空格,从第三行开始,不再继续缩进,参考示例。

  1. 运算符与下文一起换行。

  1. 方法调用的点符号与下文一起换行。

  1. 4方法调用时,多个参数,需要换行时,在逗号后进行。

  1. 在括号前不要换行

  1. 适当加空格进行格式整理(idea使用用快捷键ctrl+alt+L快速整理)

(四)OOP规范

  1. 所有覆写的方法,必须加@Override注解。可以准确判断是否覆盖成功。另外,如果在抽象中对方法签名进行修改,其实现类会马上编译报错

  1. 外部正在调用或者二方库依赖的接口,不允许修改方法签名,避免对接口调用方产生影响。接口过时必须加@Deprecated 注解,并清晰地说明采用的新接口或者新服务是什么。

  1. 调用equals方法比较时,应使用常量或确定有值的对象来调用equals方法,并且包装类对象之间的比较,全部使用 equals 方法比较

  1. 关于基本数据类型和包装数据类型的使用标准:

  1. 所有的POJO类属性必须使用包装数据类型

  1. RPC方法的返回值和参数必须使用包装数据类型

  1. 所有的局部变量推荐使用基本数据类型

  1. 构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,请放在 init 方法中

  1. 类内方法定义顺序依次是:公有方法或保护方法 > 私有方法 > getter/setter方法。

说明:公有方法是类的调用者和维护者最关心的方法,首屏展示最好;保护方法虽然只是子类关心,也可能是“模板设计模式”下的核心方法;而私有方法外部一般不需要特别关心,是一个黑盒实现;因为承载的信息价值较低,所有 Service 和 DAO 的 getter/setter 方法放在类体

  1. 循环体内,字符串的连接方式,使用 StringBuilder 的 append 方法进行扩展。

说明:反编译出的字节码文件显示每次循环都会 new 出一个 StringBuilder 对象,然后进行append 操作,最后通过 toString 方法返回 String 对象,造成内存资源浪费

  1. 类成员与方法访问控制从严:

  1. 如果不允许外部直接通过 new 来创建对象,那么构造方法必须是 private。

  1. 工具类不允许有 public 或 default 构造方法。

  1. 类非 static 成员变量并且与子类共享,必须是 protected。

  1. 类非 static 成员变量并且仅在本类使用,必须是 private。

  1. 类 static 成员变量如果仅在本类使用,必须是 private。

  1. 若是 static 成员变量,必须考虑是否为 final。

  1. 类成员方法只供类内部调用,必须是 private。

  1. 类成员方法只对继承类公开,那么限制为 protected。

说明:任何类、方法、参数、变量,严控访问范围。过于宽泛的访问范围,不利于模块解耦

(五)集合处理

  1. 在 subList 场景中,高度注意对原集合元素个数的修改,会导致子列表的遍历、增加、删除均会产生 ConcurrentModificationException 异常。并且不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator方式,如果并发操作,需要对 Iterator 对象加锁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//正例:
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
    String item = iterator.next();
    if (删除元素的条件) {
        iterator.remove();
    }
}
//反例:
List list = new ArrayList();
list.add("1");
list.add("2");
for (String item : list) {
    if ("1".equals(item)) {
        list.remove(item);
    }
}
  1. 使用集合转数组的方法,必须使用集合的 toArray(T[] array),传入的是类型完全一样的数组,大小就是 list.size()。

说明:使用 toArray 带参方法,入参分配的数组空间不够大时,toArray 方法内部将重新分配

内存空间,并返回新数组地址;如果数组元素大于实际所需,下标为[ list.size() ]的数组

元素将被置为 null,其它数组元素保持原值,因此最好将方法入参数组大小定义与集合元素

个数一致。

  1. 使用工具类 Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法,它的 add/remove/clear 方法会抛出 UnsupportedOperationException 异常。

说明:asList 的返回对象是一个 Arrays 内部类,并没有实现集合的修改方法。Arrays.asList体现的是适配器模式,只是转换接口,后台的数据仍是数组。

  1. 泛型通配符<? extends T>来接收返回的数据,此写法的泛型集合不能使用 add 方法,而<? super T>不能使用 get 方法,做为接口调用赋值时易出错。

说明:扩展说一下 PECS(Producer Extends Consumer Super)原则:第一、频繁往外读取内容的,适合用<? extends T>。第二、经常往里插入的,适合用<? super T>。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* ? extends T 表示T或T的子类
* ? super T   表示T或T的父类
* ?  表示可以是任意类型
**/
class Gent<T> {
    public void test(){
        System.out.println("gent");
    }
}
class SupC {
    public void test(){
        System.out.println("supC");
    }
}
class Bc extends SupC {
    //入参只能是SupC或SupC的子类
    public void testExtends(gent<? extends SupC> o){
        System.out.println("Bc");
    }
    //入参只能是Bc或Bc的父类
    public void testSuper(gent<? super Bc> o){
        System.out.println("Bc");
    }
    //入参可以是任意类型
    public void testSuper(gent<?> o){
        System.out.println("gent");
    }
}
  1. 合理利用好集合的有序性(sort)和稳定性(order),避免集合的无序性(unsort)和不稳定性(unorder)带来的负面影响。

说明:有序性是指遍历的结果是按某种比较规则依次排列的。稳定性指集合每次遍历的元素次序是一定的。如:ArrayList 是 order/unsort;HashMap 是 unorder/unsort;TreeSet 是order/sort。

  1. 利用 Set 元素唯一的特性,可以快速对一个集合进行去重操作,避免使用 List 的contains 方法进行遍历、对比、去重操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//两个Set比较找出交集、差集、并集
public static void  setCompare() {
    Set<Integer> result = new HashSet<Integer>();
    Set<Integer> set1 = new HashSet<Integer>() {<!-- -->{
        add(1);
        add(3);
        add(4);
    }};
    System.out.println("set1 = " + set1.toString());
     
    Set<Integer> set2 = new HashSet<Integer>() {<!-- -->{
        add(1);
        add(2);
        add(3);
    }};
    System.out.println("set2 = " + set2.toString());
    //交集:set1和set2相同的元素
    result.clear();
    result.addAll(set1);
    result.retainAll(set2);
    System.out.println("交集:" + result);
    //result结果:[1, 3]
    //差集:元素存在set1,但不存在set2
    result.clear();
    result.addAll(set1);
    result.removeAll(set2);
    System.out.println("差集:" + result);
    //result结果:[4]
     
    //并集:set1的set2的元素之和
    result.clear();
    result.addAll(set1);
    result.addAll(set2);
    System.out.println("并集:" + result);
    //result结果:[1, 2, 3, 4]
}

(六)并发处理

  1. 高并发时,同步调用应该去考量锁的性能损耗。能用无锁数据结构,就不要用锁;能锁区块,就不要锁整个方法体;能用对象锁,就不要用类锁。

说明:尽可能使加锁的代码块工作量尽可能的小,避免在锁代码块中调用 RPC 方法。

  1. 并发修改同一记录时,避免更新丢失,需要加锁。要么在应用层加锁,要么在缓存加锁,要么在数据库层使用乐观锁,使用 version 作为更新依据。

说明:如果每次访问冲突概率小于 20%,推荐使用乐观锁,否则使用悲观锁。乐观锁的重试次数不得小于 3 次。

  1. 避免 Random 实例被多线程使用,虽然共享该实例是线程安全的,但会因竞争同一seed 导致的性能下降。

说明:Random 实例包括 java.util.Random 的实例或者 Math.random()的方式。正例:在 JDK7 之后,可 以直接使用 API ThreadLocalRandom,而在 JDK7 之前,需要编码保证每个线程持有一个实例。

  1. HashMap 在容量不够进行 resize 时由于高并发可能出现死链,导致 CPU 飙升,在开发过程中可以使用其它数据结构或加锁来规避此风险

(七)控制语句

  1. 在一个 switch 块内,每个 case 要么通过 break/return 等来终止,要么注释说明程序将继续执行到哪一个 case 为止;在一个 switch 块内,都必须包含一个 default 语句并且放在最后,即使它什么代码也没有。

  1. 在 if/else/for/while/do 语句中必须使用大括号。即使只有一行代码,避免采用单行的编码方式:if (condition) statements;

  1. 表达异常的分支时,少用 if-else 方式,这种方式可以改写成:if (condition) {...return obj;}// 接着写 else 的业务逻辑代码;

说明:如果非得使用 if()...else if()...else...方式表达逻辑,避免后续代码维护困难,请勿超过 3 层。

正例:超过 3 层的 if-else 的逻辑判断代码可以使用卫语句、策略模式、状态模式等来实现,

卫语句:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//改造前(看着乱,不清楚每个逻辑分支的具体条件)
//当 a等于1
if (a == 1){
    //当 b等于2
    if (b == 2){
        ...
    } else {
        //当 b不等于1
        //c等于3
        if (c == 3){
            ...
        }
    }
}else{
    //当 a不等于1
    //当 d等于4
    if(d == 4){
        ...
    }
}
//改造后(从上到下,看着清晰明了,并清楚每个逻辑分支对应的条件)
//情况一:当 a等于1 并 b等于2
if(a == 1&&b == 2){
    ...
}
//情况二:当 a等于1 并 b不等于2 并 c等于3
if(a == 1&&b != 2&&c == 3){
    ...
}
//情况三:当 a不等于1 并 d等于4
if(a != 1&&d == 4){
    ...
}

策略模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/**
 * 实现不同动物发出不同声音
 * 如:狗--汪汪 猫--喵喵  牛--哞哞  羊--咩咩
 * @author gz
 * */
//改造前 (后期加多种动物类型,每次都需要修改共用的逻辑,易出错,且不易维护)
public class AnimalCryTest {
    private static final String DOG = "狗";
    private static final String CAR = "猫";
    private static final String CATTLE = "牛";
    private static final String SHEEP = "羊";
    /**
     * 动物的叫声
     * @param animalName 动物名称
     */
    public static void animalCry(String animalName){
        if (DOG.equals(animalName)){
            System.out.println(animalName+"----汪汪");
        }else if (CAR.equals(animalName)){
            System.out.println(animalName+"----喵喵");
        }else if (CATTLE.equals(animalName)){
            System.out.println(animalName+"----哞哞");
        }else {
            System.out.println(animalName+"----咩咩");
        }
    }
     
    public static void main(String[] args) {
        // 狗--汪汪
        animalCry(DOG);
        // 猫--喵喵
        animalCry(CAR);
        // 牛--哞哞
        animalCry(CATTLE);
        // 羊--咩咩
        animalCry(SHEEP);
    }
}
//改造后(后期加多种动物类型,只需要实现对应功能的接口,各个逻辑是相互独立的,不易出错,易维护)
/**
* 1、定义一个接口
**/
interface Animal {
    /**
     * 动物叫声
     */
    void animalCry();
}
/**
* 2、创建实现该接口的实现类
**/
class Dog implements Animal {
    @Override
    public void animalCry() {
        System.out.println("狗----汪汪");
    }
}
class Car implements Animal {
    @Override
    public void animalCry() {
        System.out.println("猫----喵喵");
    }
}
class Cattle implements Animal {
    @Override
    public void animalCry() {
        System.out.println("牛----哞哞");
    }
}
class Sheep implements Animal {
    @Override
    public void animalCry() {
        System.out.println("羊----咩咩");
    }
}
/**
* 3、多态性质,根据实例化对象的不同,调用实例化对象对应的具体方法
**/
public class AnimalCryTest {
    public static void main(String[] args) {
        // 创建狗的实例对象,并调用其对应的animalCry方法  狗--汪汪
        Animal dog = new Dog();
        dog.animalCry();
        // 创建猫的实例对象,并调用其对应的animalCry方法  猫--喵喵
        Animal car = new Car();
        car.animalCry();
        // 创建牛的实例对象,并调用其对应的animalCry方法  牛--哞哞
        Animal cattle = new Cattle();
        cattle.animalCry();
        // 创建羊的实例对象,并调用其对应的animalCry方法  羊--咩咩
        Animal sheep = new Sheep();
        sheep.animalCry();
    }
}

状态模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
/**
 * 在"投了25分钱"的状态下"转动曲柄",会售出糖果;而在"没有25分钱"的状态下"转动曲柄"会提示请先投币。
 * 四个状态:
 * 1、没有硬币状态
 * 2、投币状态
 * 3、出售糖果状态
 * 4、糖果售尽状态
 * 四个动作:
 * 1、投币
 * 2、退币
 * 3、转动出糖曲轴
 * 4、发糖
 * @author gz
 */
//改造前
public class NoPatternGumballMachine{
    /*
     * 四个状态
     */
    /**没有硬币状态*/
    private final static int NO_QUARTER = 0;
    /**投币状态*/
    private final static int HAS_QUARTER = 1;
    /**出售糖果状态*/
    private final static int SOLD = 2;
    /**糖果售尽状态*/
    private final static int SOLD_OUT = 3;
    private int state = SOLD_OUT;
    private int candyCount = 0;
    public NoPatternGumballMachine(int count) {
        this.candyCount = count;
        if(candyCount > 0)
            state = NO_QUARTER;
    }
    /*
     * 四个动作
     */
    /**
     * 投币
     */
    public void insertQuarter() {
        if(NO_QUARTER == state){
            System.out.println("投币");
            state = HAS_QUARTER;
        }
        else if(HAS_QUARTER == state){
            System.out.println("请不要重复投币!");
            returnQuarter();
        }
        else if(SOLD == state){
            System.out.println("已投币,请等待糖果");
            returnQuarter();
        }else if(SOLD_OUT == state){
            System.out.println("糖果已经售尽");
            returnQuarter();
        }
    }
    /**
     * 退币
     */
    public void ejectQuarter() {
        if(NO_QUARTER == state){
            System.out.println("没有硬币,无法弹出");
        }
        else if(HAS_QUARTER == state){
            returnQuarter();
            state = NO_QUARTER;
        }
        else if(SOLD == state){
            System.out.println("无法退币,正在发放糖果,请等待");
        }else if(SOLD_OUT == state){
            System.out.println("没有投币,无法退币");
        }
    }
    /**
     * 转动出糖曲轴
     */
    public void turnCrank() {
        if(NO_QUARTER == state){
            System.out.println("请先投币");
        }
        else if(HAS_QUARTER == state){
            System.out.println("转动曲轴,准备发糖");
            state = SOLD;
        }
        else if(SOLD == state){
            System.out.println("已按过曲轴,请等待");
        }else if(SOLD_OUT == state){
            System.out.println("糖果已经售尽");
        }
    }
    /**
     * 发糖
     */
    public void dispense() {
        if(NO_QUARTER == state){
            System.out.println("没有投币,无法发放糖果");
        }
        else if(HAS_QUARTER == state){
            System.out.println("this method don't support");
        }
        else if(SOLD == state){
            if(candyCount > 0){
                System.out.println("分发一颗糖果");
                candyCount --;
                state = NO_QUARTER;
            }
            else{
                System.out.println("抱歉,糖果已售尽");
                state = SOLD_OUT;
            }
        }else if(SOLD_OUT == state){
            System.out.println("抱歉,糖果已售尽");
        }
    }
    /**
     * 退还硬币
     */
    protected void returnQuarter() {
        System.out.println("退币……");
    }
}
//改造后
//1、定义一个接口或者抽象类,抽象出几个行为状态
public abstract class State {
    /**
     * 投币
     */
    public abstract void insertQuarter();
    /**
     * 退币
     */
    public abstract void ejectQuarter();
    /**
     * 转动出糖曲轴
     */
    public abstract void turnCrank();
    /**
     * 发糖
     */
    public abstract void dispense();
    /**
     * 退还硬币
     */
    protected void returnQuarter() {
        System.out.println("退币……");
    }
}
// 2、为每个状态实现接口或基类
/**
 * 没有硬币的状态
 */
public class NoQuarterState extends State{
    GumballMachine gumballMachine;
    public NoQuarterState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
    @Override
    public void insertQuarter() {
        System.out.println("你投入了一个硬币");
        //转换为有硬币状态
        gumballMachine.setState(gumballMachine.hasQuarterState);
    }
    @Override
    public void ejectQuarter() {
        System.out.println("没有硬币,无法弹出");
    }
    @Override
    public void turnCrank() {
        System.out.println("请先投币");
    }
    @Override
    public void dispense() {
        System.out.println("没有投币,无法发放糖果");
    }
}
/**
 * 投硬币的状态
 */
public class HasQuarterState extends State{
    GumballMachine gumballMachine;
    public HasQuarterState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
    @Override
    public void insertQuarter() {
        System.out.println("请不要重复投币!");
        returnQuarter();
    }
    @Override
    public void ejectQuarter() {
        returnQuarter();
        gumballMachine.setState(gumballMachine.noQuarterState);
    }
    @Override
    public void turnCrank() {
        System.out.println("转动曲轴,准备发糖");
        gumballMachine.setState(gumballMachine.soldState);
    }
    @Override
    public void dispense() {
        System.out.println("this method don't support");
    }
}
/**
 * 出售的状态
 */
public class SoldState extends State{
    GumballMachine gumballMachine;
    public SoldState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
    @Override
    public void insertQuarter() {
        System.out.println("已投币,请等待糖果");
        returnQuarter();
    }
    @Override
    public void ejectQuarter() {
        System.out.println("无法退币,正在发放糖果,请等待");
    }
    @Override
    public void turnCrank() {
        System.out.println("已按过曲轴,请等待");
    }
    @Override
    public void dispense() {
        int candyCount = gumballMachine.getCandyCount();
        if(candyCount > 0){
            System.out.println("分发一颗糖果");
            candyCount--;
            gumballMachine.setCandyCount(candyCount);
            if(candyCount > 0){
                gumballMachine.setState(gumballMachine.noQuarterState);
                return;
            }
        }
        System.out.println("抱歉,糖果已售尽");
        gumballMachine.setState(gumballMachine.soldOutState);
    }
}
/**
 * 售尽的状态
 */
public class SoldOutState extends State{
    GumballMachine gumballMachine;
    public SoldOutState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
    @Override
    public void insertQuarter() {
        System.out.println("糖果已经售尽");
        returnQuarter();
    }
    @Override
    public void ejectQuarter() {
        System.out.println("没有投币,无法退币");
    }
    @Override
    public void turnCrank() {
        System.out.println("糖果已经售尽");
    }
    @Override
    public void dispense() {
        System.out.println("糖果已经售尽");
    }
}
//3、将糖果机的动作委托到状态类
public class GumballMachine extends State{
    public State noQuarterState = new NoQuarterState(this);
    public State hasQuarterState = new HasQuarterState(this);
    public State soldState = new SoldState(this);
    public State soldOutState = new SoldOutState(this);
    private State state = soldOutState;
    private int candyCount = 0;
    public GumballMachine(int count) {
        this.candyCount = count;
        if(count > 0)
            setState(noQuarterState);
    }
    @Override
    public void insertQuarter() {
        state.insertQuarter();
    }
    @Override
    public void ejectQuarter() {
        state.ejectQuarter();
    }
    @Override
    public void turnCrank() {
        state.turnCrank();
    }
    @Override
    public void dispense() {
        state.dispense();
    }
    public void setState(State state) {
        this.state = state;
    }
    public State getState() {
        return state;
    }
    public void setCandyCount(int candyCount) {
        this.candyCount = candyCount;
    }
    public int getCandyCount() {
        return candyCount;
    }
}

从代码里面可以看出,糖果机根据此刻不同的状态,而使对应的动作呈现不同的结果。这份代码已经可以满足我们的基本需求,但稍微思考一下,你会觉得这种实现代码似乎,功能太复杂了,扩展性很差,没有面向对象的风格。

假设由于新需求,要增加一种状态,那每个动作方法我们都需要修改,都要重新增加一条else语句。而如果需求变更,某个状态下的动作需要修改,我们也要同时改动四个方法。这样的工作将是繁琐而头大的。

可以发现,这种模式下,糖果机根本不需要清楚状态的改变,它只用调用状态的方法就行。状态的改变是在状态内部发生的。这就是"状态模式"。

如果此时再增加一种状态,糖果机不需要做任何改变,我们只需要再增加一个状态类,然后在相关的状态类方法里面增加转换的过程即可

  1. 除常用方法(如 getXxx/isXxx)等外,不要在条件判断中执行其它复杂的语句,将复杂逻辑判断的结果赋值给一个有意义的布尔变量名,以提高可读性。

说明:很多 if 语句内的逻辑相当复杂,阅读者需要分析条件表达式的最终结果,才能明确什么样的条件执行什么样的语句,那么,如果阅读者分析逻辑表达式错误呢?

1
2
3
4
5
6
7
8
9
10
正例:
// 伪代码如下
final boolean existed = (file.open(fileName, "w") != null) && (...) || (...);
if (existed) {
...
}
反例:
if ((file.open(fileName, "w") != null) && (...) || (...)) {
...
}

(八)注释规范

  1. 类、类属性、类方法的注释必须使用 Javadoc 规范,使用/**内容*/格式,不得使用// xxx 方式

  1. 所有的抽象方法(包括接口中的方法)必须要用 Javadoc 注释、除了返回值、参数、异常说明外,还必须指出该方法做什么事情,实现什么功能。

  1. 方法内部单行注释,在被注释语句上方另起一行,使用//注释。方法内部多行注释使用/ /注释,注意与代码对齐。

  1. 所有的枚举类型字段必须要有注释,说明每个数据项的用途。

  1. 代码修改的同时,注释也要进行相应的修改,尤其是参数、返回值、异常、核心逻辑等的修改。代码和注释要同步更新

  1. 对于注释的要求:第一、能够准确反应设计思想和代码逻辑;第二、能够描述业务含义,使别的程序员能够迅速了解到代码背后的信息。注释要尽可能精简准确、表达到位,要避免过多过滥的注释。

  1. 特殊注释标记,请注明标记人与标记时间。注意及时处理这些标记,通过标记扫描,经常清理此类标记。线上故障有时候就是来源于这些标记处的代码。

  1. 待办事宜(TODO):( 标记人,标记时间,[预计处理时间])表示需要实现,但目前还未实现的功能。这实际上是一个 Javadoc 的标签,目前的 Javadoc还没有实现,但已经被广泛使用。只能应用于类,接口和方法(因为它是一个 Javadoc 标签)。

  1. 错误,不能工作(FIXME):(标记人,标记时间,[预计处理时间])在注释中用 FIXME 标记某代码是错误的,而且不能工作,需要及时纠正的情况。

(九)其他

  1. 获取当前毫秒数 System.currentTimeMillis(); 而不是 new Date().getTime();说明:如果想获取更加精确的纳秒级时间值,使用 System.nanoTime()的方式。在 JDK8 中,针对统计时间等场景,推荐使用 Instant 类

  1. 不要在controller层加任何复杂的逻辑

  1. 任何数据结构的构造或初始化,都应指定大小,避免数据结构无限增长吃光内存

  1. 一个方法体不要过长,要对逻辑进行拆分,尽量不要超过80行

Tags:java,编程入门,开发规范  
责任编辑:admin
请文明参与讨论,禁止漫骂攻击。 昵称:注册  登录
[ 查看全部 ] 网友评论
    没有任何评论
关于我们 - 联系我们 - 广告服务 - 友情链接 - 网站地图 - 版权声明 - 在线帮助 - 文章列表
返回顶部
刷新页面
下到页底
晶体管查询