共变,不变和反变
公变和反变,又称协变和逆变,要深入理解它们,我建议从它们所解决的问题出发,然后再从技术层面看它们是怎么实现的。
用一句话概括,协变和逆变为了更好的写通用算法。优秀的程序员的都是懒的,能一下做完的事情绝对不重复。
咱们举个例子,说有一个豆子交易员,他牵线搭桥,把豆子从生产者交易到消费者手里,然后从中抽一成的佣金。这个算法是通用的,一方面它既适用于普通的豆子生产者也能处理生产特别豆子的,另一方面它既支持豆子消费者又能交易给所有农产品通吃的更广大消费者。
function exchange(producer
val bean = producer.getBean();
getMoney(bean.getBeanPrice() * 0.1);
consumer.consume(bean);
}
我们接下来具体看看在什么情况下能用这个算法。现在我们有三个类,分别是父类,农产品(product),中间的豆子 (bean),和子类绿豆 (greenBean)。
先看消费端,对于这个交易员来说,如果来的消费者是农产品通吃,那么给交易员一个consumer
再看生产端,对于交易员来说,如果来的生产者是产绿豆的,那么给交易员一个producer
消费端,看逆变,农产品是豆子的父类,而农产品的消费者确是豆子消费者的子类,consumer
这一逆一协中的奥秘就是,要想写出来通用的算法,当你面对的是生产方的时候,条件要严,而当面对的是消费者的时候,条件要松。交易员把好严生产松消费的关,生意就好做,算法写一个就完事。
最后,不同的编程语言有不同的实现方式,不管是java中的super/extends,还是c#中的in, out,还是scala中的+/-,说的都是一个事。如果你还不满足,想挖的更深,这里有一个从范畴论的角度开讲的,http://tomasp.net/blog/variance-explained.aspx/。