20220510
解决方案:类、对象、方法
大概来说,一个程序运行上述游戏需要以下几个部分组成
1.算法
设置一个初始布局状态,打印这个布局状态,当用户想看下一代的时候根据规则更新布局状态并打印当前状态
2.类和对象
一个configuration布局实体/实例/对象,类型是Life,我们让这个对象使用Life的3个方法:initialize将会初始化一个最开始的状态,print打印当前布局,update让布局更新为下一代
一个Clients类,用于访问前面的对象,可以声明前面这些类的实例。一般可以叫做Main活着xxxTest之类的都ok
3.规范
当编写一个客户端程序的时候,一个很重要的点是我们不需要知道数据是如何存储的,也不需要知道这些方法是如何被编程的。这是自顶向下设计非常重要的一个转变,写代码多了就会熟悉这种思路。这通常被称为information hiding
当我们实现Life类的时候,我们才需要决定如何存储这些数据,以及如何实现这些方法,这些数据和方法对Life来说都是私有的,client程序不需要知道这些,只需要访问公开的方法即可
| 0 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 | import java.util.Scanner; public class Main0510_1 {     /**      * 前置条件:用户指定了初始布局      * 预期结果:根据规则打印所有存活的细胞      * 依赖:Life类和成员方法initialize、print、update      */     public static void main(String[] args) {         Life conf = new Life();         instructions();         conf.initialize();         conf.print();         System.out.println("是否继续下一代?");         while (userSaysYes()) {             conf.update();             conf.print();             System.out.println("是否继续下一代?");         }     }     private static void instructions() {         System.out.println("打印使用指南");     }     public static boolean userSaysYes() {         Scanner in = new Scanner(System.in);         boolean userInput = in.nextBoolean();         return userInput;     } } | 
编程中一个相当重要的道德行为就是命名规范,尽管数据和算法之前就存在了,但只有当给他们有意义的名字的时候,他们才能被正常的阅读。为了精确的理解每个变量和方法的作用,有时需要给类、变量、方法编写文档来说明。它们的名字应当简洁且清晰的精确表示他们的含义,寻找一个好的变量名并不总是一个简单的工作
使用小写字母l、大写字母O、数字0的时候需要额外的注意,底下是一个蛋疼的例子(吐槽下苹果上对于括号的渲染,也是个大坑)
| 0 1 2 | l = 1; x = 1; x = l; x = O; O = 0; | 
注释要避免解释代码本身的动作,解释Why,而不是解释How
| 0 1 2 3 |  count ++ //count自增1  count ++ //增加xxx的计数,这里的xxx是上下文相关的,count的实际含义,虽然我一般会直接用xxxCount来避免这种注释 | 
编程原则:
- 让程序的阅读起来更容易,因为一个程序的阅读时间要远多于编写时间
- 不要丢掉全局视野
- 用类来对基础概念进行建模
- 每个方法都应该只做一件事,但做到极致
- 每个类都应该隐藏一些东西
- 保持上下文简洁、如非必要,不要用全局变量
- 尽可能的避免边际效应,如果一定要用全局变量,写文档
编码&测试&重构
stub打桩技术,快速让主程序通过编译或为了方便测试,可以先搭架子
| 0 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 | import java.util.Scanner; public class Main0510_1 {     /**      * 前置条件:用户指定了初始布局      * 预期结果:根据规则打印所有存活的细胞      * 依赖:Life类和成员方法initialize、print、update      */     public static void main(String[] args) {         Life conf = new Life();         instructions();         conf.initialize();         conf.print();         System.out.println("是否继续下一代?");         while (userSaysYes()) {             conf.update();             conf.print();             System.out.println("是否继续下一代?");         }     }     private static void instructions() {         System.out.println("打印使用指南");     }     public static boolean userSaysYes() {         Scanner in = new Scanner(System.in);         boolean userInput = in.nextBoolean();         return userInput;     } } class Life {     public void initialize() {     }     public void print() {     }     public void update() {     } } | 
20220510结束,耗时1小时10分钟
顺带一提,vscode Code-runner跑代码乱码可以这样解决
| 0 1 2 3 4 |     "code-runner.executorMap": {         "java": "cd $dir && javac -encoding utf-8 $fileName && java -Dfile.encoding=UTF-8 $fileNameWithoutExt"     } |