给前端介绍对象啦!(TypeScript 版)(三)

阅读数:2 2020 年 1 月 7 日 15:39

给前端介绍对象啦!(TypeScript版)(三)

多态:我就是我,不一样的烟火

多态是指同一个方法在子类中具有不同表现形式。例如:Dog 类和 Cat 类都有 eat ()/say () 方法,尽管都是来自 Animal 定义的 eat ()/say () 方法,但运行结果完全不同。
(温馨提示:左右滑动可查看全部代码)

复制代码
class Cat extends Animal {
public eat() {// 多态 扩展原方法
super.eat();
console.log("I like eating fish");
}
public say() {
console.log("Miao~");
}
public catchMouse() {
//...
}
}

测试用例:

复制代码
let myCat: Animal = new Cat("XiaoHua", 3);
myCat.eat();//I am eating someting I like eating fish
myCat.say();//Miao~

接口

接口:没有规矩不成方圆

接口即规范,规定了某种能力必须要实现的方法。例如:Flyable 接口规定了具有飞行能力必须实现 fly() 方法。Bird 和 Plane 类都实现了 Flyable 接口,具有飞行能力。
(温馨提示:左右滑动可查看全部代码)

复制代码
interface Flyable {
fly();
}
interface catchBug {
catchBug();
}
class Bird extends Animal implements Flyable,catchBug {
public say() {
console.log("Ji~Ji~Zha~Zha~");
}
public fly() {
console.log("I am flying with flapping my wings");
}
public catchBug() {
//...
}
}
class Plane implements Flyable {
fly() {
console.log("I am flying with my engines");
}
takePeople() {
//...
}
}

测试用例:
(温馨提示:左右滑动可查看全部代码)

复制代码
let flyable1: Flyable = new Bird("Polly", 1);
flyable1.fly(); //I am flying with flapping my wings
// flyable1.eat();// 编译报错: 不存在 eat()
let flyable2: Flyable = new Plane();
flyable2.fly();//I am flying with my engines

抽象类与接口:有同有异

抽象类和接口很类似,都有未实现的方法,等待其他类去实现。区别是:抽象类可以有一些成员的实现,而接口没有成员的实现;一个类只能继承自一个抽象类,但可以实现多个接口。例如:Animal 类,有抽象方法 say(),也有已实现的方法;上面 Bird 类只能继承自一个类,但又同时实现了 flyable()/catchBug() 两个接口。

OOP 设计原则

李氏替换原则:父债可以子来偿

所有引用基类的地方必须能透明的使用其子类的对象,因为子类的对象具有基类所有的属性和方法。(注:基类是指父类 / 父类的父类等)但反过来就不行了,有需要子类的地方,基类未必就能适应。例如:上面代码中,我们可以将 Dog 对象和 Cat 对象赋值给了 Animal 类型的变量。下面代码中,People 构造函数需要一个 Animal 类型的参数,我们传入了 Dog 类型的对象。
(温馨提示:左右滑动可查看全部代码)

复制代码
class People extends Animal{
constructor(public name: string, public age: number,public pet: Animal) {
super(name,age);
};
public say(){
console.log(`My name is ${this.name}, I am ${this.age} years old, my pet's name is ${this.pet.name}`);
}
}

测试用例:
(温馨提示:左右滑动可查看全部代码)

复制代码
let myBrother: People = new People("XiaoMing", 18, new Dog("GouDan", 2));
myBrother.say();//My name is XiaoMing, I am 12 years old, my pet's name is GouDan
console.log('totalNum='+Animal.totalNum);//totalNum=5 //Dog/Cat/Bird/Dog/People/

依赖倒置原则:面向接口编程,大家都依赖接口

在无接口的代码组织中,是高层模块依赖低层模块。如果按照面向对象编程依赖倒置原则,高层模块和低层模块不互相依赖,他们都依赖于其接口 / 抽象类。例如:如果不存在接口,直接调用 Bird 类 /Plane 类的 fly() 方法,那么调用者便依赖于 Bird 类 /Plane 类。在上面例子中采用了接口编程,调用者的调用依赖于 Flyable() 接口;Bird 类和 Plane 类的实现都依赖于 Flyable() 接口。

请看下图,原本高层模块向下依赖的箭头,变为低层模块向上依赖的箭头。这就是依赖倒置名称的由来。

无接口:
给前端介绍对象啦!(TypeScript版)(三)
有接口,依赖倒置:

给前端介绍对象啦!(TypeScript版)(三)

其他设计原则

单一职责、开闭原则、接口隔离、迪米特法则等其他 OOP 设计原则呢,后会有期。

总结

在一切皆对象的世界中,我们已经学习了面向对象三大特征——封装、继承、多态,和两条面向对象设计原则——李氏替换原则、依赖倒置原则。后面有机会再介绍其他 OOP 设计原则和 GoF 设计模式。

本转载自 Think 体验设计公众号。

原文链接: https://mp.weixin.qq.com/s/CXaasAzRMk3mD_waWv8DHQ

评论

发布