代码之道 - change or not change
1. 前言
谈论代码之道可能有些言过其实,我更倾向于将其视为一种交流与分享的机会,以便我们能够共同学习并取得进步,今天我主要从变与不变的角度来和大家分享一下我写代码的一些心得
2. 从设计模式说起
设计模式大家可谓是久闻大名,那到底设计模式解决了什么样的问题呢?
- 拿一个装饰器模式看看
js
// 展示接口
public interface Showable {
public void show();
}
public class Girl implements Showable {
@Override
public void show() {
System.out.print("女生的脸");
}
}
public class Decorator implements Showable{
//被装饰的展示者
Showable showable;
public Decorator(Showable showable) {
//构造时注入被装饰者
this.showable = showable;
}
@Override
public void show() {
System.out.print("磨皮");
//化妆品粉饰开始
showable.show();
//被装饰者的原生展示方法
System.out.print("美颜");
//粉饰结束
}
}
public class Client {
public static void main(String[] args) {
//用装饰器包裹女孩后再展示
new Decorator(new Girl()).show();
//运行结果:粉饰【女生的脸】
}
}
可以看到装饰器模式的本质其实就是在不改变原来的代码上,为方法加上新的功能。
但是为什么需要这样呢?你可能会说我在原来的代码上增加两行代码不好吗?
js
public class Girl implements Showable {
@Override
public void show() {
System.out.print("磨皮");
System.out.print("女生的脸");
System.out.print("美颜");
}
}
但是这样这个方法就被限定在磨皮
和 美颜
上面了,如果这个女孩在星期一想 磨皮
和 美颜
,在星期二想祛痘
和 遮瑕
那就又需要新写一个Girl
类了。
也就是最本质是要清楚 女生的脸
一般情况下是 不变的 ,磨皮
、美颜
这些东西是变化的,所以核心是抽象出变化和不变的东西。
我们常常使用的 AOP
其实也可以看作是一种装饰器,只不过由 AOP
实现的更加强大,可以通过注解的方式批量为方法增强功能。
- 再看看设计模式中的工厂吧
js
public abstract class Entity {
//敌人的坐标
protected int x;
protected int y;
//初始化坐标
public Enemy(int x,int y) {
this.x = x;
this.y = Y;
}
//抽象方法,在地图上绘制
public abstract void show();
}
// 飞机类
public class Air extends Entity {
public Air(int x,int y){
super(x,y);//调用父类构造方法初始化坐标
}
@Override
public void show(){
System.out.println("绘制飞机于上层图层,出现坐标:"+ x + "," + y);
System.out.println("飞机出来了");
}
}
// 车辆
public class Car extends Entity {
public Tank(int x,int y){
super(x,y);//调用父类构造方法初始化坐标
}
@Override
public void show(){
System.out.println("绘制汽车于下层图层,出现坐标:"+x + "," + y);
System.out.println("汽车向玩家出来了");
}
}
其实也是一样的道理,工厂其实就是抽离了对象不变的本质 实体都有 x y 坐标,并且都会在地图上绘制
所以设计模式其实没有帮你解决任何问题,它是对一类相似问题的抽象的总结,当你看到同样的问题时,你自然就知道选用那种设计模式来让你的代码变得更加简单。
- 再来看一个更简单的例子
js
public class MultiplicationTable {
public static void main(String[] args) {
System.out.println("1*1=1");
System.out.println("1*2=2\t2*2=4");
System.out.println("1*3=3\t2*3=6\t3*3=9");
// ... 省略
}
}
public class MultiplicationTable {
public static void main(String[] args) {
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= i; j++) {
System.out.print(j + "*" + i + "=" + (i * j) + "\t");
}
}
}
}
程序界常流传的一个笑话就是,老师让学生写代码输出99乘法表,结果学生直接用手写的方法输出了出来。
这其实就是初学者无法对问题进行更本质的抽象,找到事物中变与不变的部分,所以才造成了这种啼笑皆非的情况。
评价一个代码的好坏,其中的一个方面我想就是有没有对事物或者问题有更本质的思考,提炼出了事物和问题之间不变的共性
3. 那么写代码更核心问题到底是什么
我觉得写好代码有时就和解数学题一样, 都是需要抽象出事物的变和不变的部分,但是最核心的问题其实还是没有对事物抽象的能力,找到一个事物和问题之间的共性其实是很难的。
你可能需要各方面知识都需要有涉猎,就像如果不知道方程,可能就只能使用穷举的方式来解决鸡兔同笼的问题了。
我想很多时候我们写代码时都忽略了需要仔细思考问题本身的共性,而不是直接去解决问题。用蛮力来解决问题很多时候可能只能是事倍功半。
提取出问题和事物的共性,寻求一个问题的最优解,避免重复的体力劳动,可能会让日常的工作变得更加轻松。