提到面向对象的好处,一些人脑中可能会冒出:封装继承多态封装
封装:通过类,为数据和方法,提供统一的上下文
但是,函数名,同样也可以提供上下文,并且可以通过一种叫柯里化的技巧,保存某些字段,从而实现类中成员变量的效果
面向对象在封装中,没有体现出明显的优势 😔
继承:其本质为复用,而通过函数,也可以实现复用 😔
最后是多态:相同的接口,不同的行为
比如一个计算器的例子:
public interface Operation { int operate(int a, int b); }
public class Add implements Operation { public int operate(int a, int b) { return a + b; } }
public class Sub implements Operation { public int operate(int a, int b) { return a - b; } }
public class Mul implements Operation { public int operate(int a, int b) { return a * b; } }
public class Div implements Operation { public int operate(int a, int b) { return a / b; } }
// 工厂模式:可以将(创建对象逻辑)与(具体业务逻辑)进行分离
public class OperationFactory {
static Map<String, Operation> opMap = new HashMap<>();
static {
opMap.put("add", new Add());
opMap.put("sub", new Sub());
opMap.put("mul", new Mul());
opMap.put("div", new Div());
}
public static Operation getOp(String op) {
return opMap.get(op);
}
}
使用方式
public static void main(String[] args) {
Operation op = OperationFactory.getOp("add");
Integer res = Main.calculate(op, 1, 2);
System.out.println(res);
}
public static Integer calculate (Operation op, int a, int b) {
return op != null ? op.operate(a, b): null;
}
在 Javascript 中,你同样可以将运算逻辑,存储到 map 中
const opMap = {
add: (a, b) => a + b,
sub: (a, b) => a - b,
mul: (a, b) => a * b,
div: (a, b) => a / b
};
const op = opMap['add'];
const res = op(1, 2);
console.log(res);
区别就在于:一个存储的是对象(类的实例),另一个存储的是函数
但是,对象所具有的上下文(字段、方法)(主要是字段)更加明显
这里好像还看不出多态的所具有哪些明显的好处
接口当作参数
接口当作参数,相同功能,可有不同实现,从而达到动态替换
动态替换的好处:在使用函数时,可以将(变与不变)进行隔离,从而达到函数的复用(这一点已经在 calculate 函数中看到了)
变化的东西进行抽取出来的好处:类比于拼积木,将具有相同功能,但可以有不同的实现的对象,拼接到一起
独立开发,只关注业务逻辑
对象存在的目的是为了完成某项功能
一个对象,如果可以完成某个功能的,但具有前提,该前提是:借助(依赖)另一个东西,否则无法做到(巧妇难为无米之炊)
如果我不依赖于具体实现,而是依赖于接口呢?
那么,这意味着,可以独立开发 ⭐️
在函数中,调用接口的方法(我不关心接口内的方法是如何实现的),接口内的方法,留着别人来实现吧~
就像访问数据库,我要获取某个表的所有字段,然后对这些字段进行操作
获取所有字段的逻辑,定义为一个接口 getAll(),至少具体实现,我不关系,交给下层去做吧~ 用的是 Mysql 还是 Oracle,我也不关系,因为我可以对下层的实现进行替换
使得我可以只关注于业务逻辑⭐️⭐️⭐️,独立开发⭐️,并且将对象,当作拼积木一样,进行拼接,完成想要的功能