最近因为开发一个项目的关系在研究《Head First设计模式》,想从中找到一些灵感,虽然之前也看过,但是每次学习,都会有新的理解和感悟,非常感谢作者提供了这样一本让我受益匪浅的书!
面向对象程序设计(注意这里是面向对象,而不是基于对象)的一个很重要的设计原则就是:针对接口编程,而不是针对实现编程!可就是这样一句句很浅显的话,确包含了很多面向对象的知识在里面!
“什么是针对接口编程呢?”,“针对接口编程的真正意思是”针对超类型编程“。所以这里的”接口“就不再仅仅指的是java中的interface,还包括了抽象类,”超类型“在这里就是指”interface“和”abstract“类,当然不包括普通用于继承的类,因为普通的类虽然可以继承但是无法实现”多态“。而”多态“,正是”针对接口编程“的关键之所在!
”什么是多态呢?“,多态(Polymorphism)按字面的意思就是“多种状态”,指同一个实体同时具有多种形式。在面向对象语言中,接口的多种不同的实现方式即为多态。引用Charlie Calverts对多态的描述——多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。如果一个语言只支持类而不支持多态,只能说明它是基于对象的,而不是面向对象的。利用多态,程序可以针对”超类型“编程,执行时会根据实际状况执行到真正的行为,不会被绑死在超类型的行为上。
以下是非多态和多态的对比:
例子:假设有一个类Animal,有两个子类(Dog与Cat)继承Animal:
针对实现编程是这样做的:
class Animal { String name; String sex; public void Display() { System.out.println("name =" + name + "sex =" + sex); } public void Sound() { System.out.println("make sound!"); } } class Dog extends Animal{ public void Sound() { System.out.println("wang...wang...wang..."); } } class Cat extends Animal{ public void Sound() { System.out.println("miao...miao...miao..."); } } public class AnimalTest { public static void main(String[] args) { Dog dog = new Dog(); dog.Sound(); Cat cat = new Cat(); cat.Sound(); } }
而”针对接口/超类型编程"做法如下:
class Animal { String name; String sex; public void Display() { System.out.println("name =" + name + "sex =" + sex); } public void Sound() { System.out.println("make sound!"); } } class Dog extends Animal{ public void Sound() { System.out.println("wang...wang...wang..."); } } class Cat extends Animal{ public void Sound() { System.out.println("miao...miao...miao..."); } } public class AnimalTest { public static void main(String[] args) { Animal animal = new Dog(); animal.Sound(); animal = new Cat(); animal.Sound(); } }
多态总结:
(1)多态是通过:
1. 接口 和 实现接口并覆盖接口中同一方法的几不同的类体现的
2. 父类 和 继承父类并覆盖父类中同一方法的几个不同子类实现的.
(2)通过将子类对象引用赋值给超类对象引用变量来实现动态方法调用。
(3)java 的这种机制遵循一个原则:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。
1. 如果a是类A的一个引用,那么,a可以指向类A的一个实例,或者说指向类A的一个子类。
2. 如果a是接口A的一个引用,那么,a必须指向实现了接口A的一个类的实例。