面向对象编程语言可以总结为实现了类和对象的概念,并且灵活具有着  封装 继承 抽象 多态四个特性的编程语言

今天,我们就来看看这个这四大特性的必要性

1.封装(Encapsulation)

封装是将类或者对象的数据进行保护,只对外暴露有限的访问接口,让外部只能通过类提供的方法来访问其中的数据

假设下面的一个类

public class Wallet {

private String id;

private long createTime;

private BigDecimal balance;

private long balanceLastModifiedTime;

// …省略其他属性…

public Wallet() {

this.id = IdGenerator.getInstance().generate();

this.createTime = System.currentTimeMillis();

this.balance = BigDecimal.ZERO;

this.balanceLastModifiedTime = System.currentTimeMillis();

}

// 注意:下面对get方法做了代码折叠,是为了减少代码所占文章的篇幅

public String getId() { return this.id; }

public long getCreateTime() { return this.createTime; }

public BigDecimal getBalance() { return this.balance; }

public long getBalanceLastModifiedTime() { return this.balanceLastModifiedTime;  }

public void increaseBalance(BigDecimal increasedAmount) {

if (increasedAmount.compareTo(BigDecimal.ZERO) < 0) {

throw new InvalidAmountException(“…”);

}

this.balance.add(increasedAmount);

this.balanceLastModifiedTime = System.currentTimeMillis();

}

public void decreaseBalance(BigDecimal decreasedAmount) {

if (decreasedAmount.compareTo(BigDecimal.ZERO) < 0) {

throw new InvalidAmountException(“…”);

}

if (decreasedAmount.compareTo(this.balance) > 0) {

throw new InsufficientAmountException(“…”);

}

this.balance.subtract(decreasedAmount);

this.balanceLastModifiedTime = System.currentTimeMillis();

}

}

上面的类中,具有四个属性 id createTime balance balanceLastModifiedTime

而其只能调用以下六个方法来对数据进行访问修改

getId

getcreateTime

getBalance

getBalanceLastModifiedTime

increaseBalance

decreaseBalance

其中id和创建时间是在类生成的时候就创建好的,所以并不需要可以设置属性的方法避免被篡改,对于修改balance和ModifiedTime这两个属性,则是封装在了increaseBalance和decreaseBalance方法上

不对外暴露任何修改这个属性的方法和业务细节,保证了数据的一致性

这就是封装的特性,只将用户需要知道的属性进行暴露,避免其他人的篡改,为了实现这个特性,一般要求编程语言提供权限控制的功能

比如 private public 等,而利用权限控制功能,就可以避免数据的被奇葩的篡改了,保护了数据的安全,而且方便了其他调用这个类的人员的易用性

总结一下来说:封装降低了数据被篡改的风险,并提高了类的易用性

2.抽象(Abstraction)

抽象是为了调用这不必要知道方法的具体实现,只需要知道方法实现了什么功能

面向对象编程语言中,利用一般编程语言自己提供的interface关键字或者抽象类来实现这一特性

public interface IPictureStorage {

void savePicture(Picture picture);

Image getPicture(String pictureId);

void deletePicture(String pictureId);

void modifyMetaInfo(String pictureId, PictureMetaInfo metaInfo);

}

public class PictureStorage implements IPictureStorage {

// …省略其他属性…

@Override

public void savePicture(Picture picture) { … }

@Override

public Image getPicture(String pictureId) { … }

@Override

public void deletePicture(String pictureId) { … }

@Override

public void modifyMetaInfo(String pictureId, PictureMetaInfo metaInfo) { … }

}

这段代码中,使用了interface实现了一个IPictureStorage的抽象类,这样调用在调用的时候,只需要看到这个抽象类就可以了,知道了传入什么,可以获取什么,并不需要关心具体的实现方式

其实抽象这个特性更像是一种概念,其实即使没有IPictureStorage这个抽象类,单纯的PictureStorage类就是满足抽象特性的

其实,只要注释和文档或者方法本身的命名足够好,能够一眼知道怎么使用,就是具有抽象性的,抽象这个概念非常的广泛,故时常不被认为是面向对象编程的特性之一

那么抽象可以解决的体问题,就是上面说的,我们只需要关注功能点,而不用关注如何去实现,方便我们去过滤掉很多非必要的信息

在现实中,而很多设计原则都体现了抽象这个设计思想,譬如 基于接口而非实现 开闭原则(对于扩展开房,对于修改关闭) 代码解耦等

当然,在书写类名的时候,为了满足抽象方法,getAliyunPictureUrl()就不太符合抽象思想,因为一旦不再在阿里云平台上存储了,名字就不符合了

故,建议起为 getPrictureUrl更好

3.继承(Inheritance)

学习完了封装和抽象,继承这就很简单了,简单描述为 is-a 我是一个人,继承可以分为两种模式,单继承和多继承,单继承表示一个子类只继承一个父类

为了实现继承的概念,,Java体用了extends,在C++中使用了冒号 class B:public A

Python实现paraentheses(),有些编程语言支持了单继承,有些则实现了多继承

继承的意义在于代码复用上,子类可以直接调用父类中已有的方法,避免代码多写,而且继承关系可以有效的让调用者去理解关系

但是过度使用继承,会导致降低代码的可维护性,一个类的代码需要翻阅多个父类才能完全理解

4.多态(Polymorphism)

多条是指子类可以替换父类,在实际运行中,去调用的是子类的方法,例如

public class DynamicArray {

private static final int DEFAULT_CAPACITY = 10;

protected int size = 0;

protected int capacity = DEFAULT_CAPACITY;

protected Integer[] elements = new Integer[DEFAULT_CAPACITY];

public int size() { return this.size; }

public Integer get(int index) { return elements[index];}

//…省略n多方法…

public void add(Integer e) {

ensureCapacity();

elements[size++] = e;

}

protected void ensureCapacity() {

//…如果数组满了就扩容…代码省略…

}

}

public class SortedDynamicArray extends DynamicArray {

@Override

public void add(Integer e) {

ensureCapacity();

int i;

for (i = size-1; i>=0; –i) { //保证数组中的数据有序

if (elements[i] > e) {

elements[i+1] = elements[i];

} else {

break;

}

}

elements[i+1] = e;

++size;

}

}

public class Example {

public static void test(DynamicArray dynamicArray) {

dynamicArray.add(5);

dynamicArray.add(1);

dynamicArray.add(3);

for (int i = 0; i < dynamicArray.size(); ++i) {

System.out.println(dynamicArray.get(i));

}

}

public static void main(String args[]) {

DynamicArray dynamicArray = new SortedDynamicArray();

test(dynamicArray); // 打印结果:1、3、5

}

}

上面可以看出,编程语言要实现多条,就需要支持父类对象可以直接引用子类对象 并且支持继承,支持重写

上面就是实际调用了子类的add方法

除了常见的继承,还有着接口类书写来实现多态,duck-typing机制来实现多态

如何使用接口来实现多态呢,很简单

public interface Iterator {

String hasNext();

String next();

String remove();

}

public class Array implements Iterator {

private String[] data;

public String hasNext() { … }

public String next() { … }

public String remove() { … }

//…省略其他方法…

}

public class LinkedList implements Iterator {

private LinkedListNode head;

public String hasNext() { … }

public String next() { … }

public String remove() { … }

//…省略其他方法…

}

public class Demo {

private static void print(Iterator iterator) {

while (iterator.hasNext()) {

System.out.println(iterator.next());

}

}

public static void main(String[] args) {

Iterator arrayIterator = new Array();

print(arrayIterator);

Iterator linkedListIterator = new LinkedList();

print(linkedListIterator);

}

}

那么,在需要调取Iterator的时候,就可以通过传递不同的实现类来调用不同的实现

这就是多态

dukc-typing方法来实现多态,拿一段python代码来展示

class Logger:

def record(self):

print(“I write a log into file.”)

class DB:

def record(self):

print(“I insert data into db. ”)

def test(recorder):

recorder.record()

def demo():

logger = Logger()

db = DB()

test(logger)

test(db)

duck-typing实现多态的方式很灵活,Logger和DB没有任何关系,也不是继承关系,也不是接口和实现,只要定义了这个方法,就可以传入

多态的特性讲完了,意义何在

还是为了提高代码的复用性和可扩展性,而且很多设计模式 设计原则,比如基于接口而非实现,依赖倒置,里氏替换原则,都是基于的多态

本章的重点为

1.封装

只暴露有限的接口,避免被篡改,同时提高了代码的易用性,但是需要编程语言提供相对应的权限控制语法来进行支持

2.抽象特性

如何去隐藏信息,保护数据,是封装的功能,抽象则是将具体的方法实现去隐藏掉,让使用者只关心方法的使用

提高了代码的可扩展性,维护性,减少了改动范围

3.继承特性

is-a关系,分为两种模式,单继承和多继承,单继承只有一个子类继承父类,多继承则是一个子类可以继承多个父类

4.多态特性

子类可以替换父类,在实际运行中,调用子类的方法实现,多态这种特性需要编程语言提供特殊的语法机制来实现,比如继承,接口类,duck-typing,多态可以提高代码的扩展性和复用性

1.熟悉的编程语言是否支持多重继承,为何不支持,支持了如何避免多重继承的副作用

2.熟悉的编程语言是否都支持四大特性,如何支持的,如何实现的

1.对于这个问题,我比较熟悉Java,是不支持多重继承的,毕竟有一个经典的钻石问题,在多重继承的时候,可能因为继承的多个父类都具有相同的属性,从而导致子类无法指定使用哪个父类的方法,从而出现了歧义

2.Java本身是支持四大特性,如上面所说,封装通过类,继承通过extends,多态通过子类转换为父类调用,抽象通过接口类和抽象类实现了

发表评论

邮箱地址不会被公开。 必填项已用*标注