什么是抽象

大多数人对“抽象”一词的第一反应是形容词的抽象(abstract),于是总不自觉地将之与“深奥”、“模糊”、“不直观”、“不具体”等相关联,这固非大谬,然而在编程设计中,人们关注或强调的抽象更多地当是名词的抽象(abstraction)或动词的抽象(abstract,指“抽象化”)。比如著名的针对接口编程(programming to interface)原则、依赖反转(Dependency Inversion)原则,本质上都是提倡针对抽象编程,这样做的好处暂且不提,代码一定会因此变得更不直观、更难操纵、更不自然、更难理解吗?恐怕未必吧。如果说增加的抽象层(abstraction layer)(比如abstract class、interface等)有时会制造一些复杂的话(但最终目的是为了减少复杂),那么普通API的调用则是再常见不过了。相比一个API清晰的接口和明确的规范,它的冗长、复杂的实现代码虽然更加具体,但不是更难以把握和理解吗?


设计(不限于编程设计)中的抽象与口语中的抽象并不完全等同,由于其相对性和普适性,看似具体的事物也有抽象的一面,看似抽象的事物也有具体的一面。在提及抽象时,建议少通过形容词(abstract)来联想,多用名词(abstraction)或动词(抽象化)。或者更好地,根据上下文把抽象直接替换为“规范”(specification)、“约定”(convention)、“协议”(protocol)、“概念”(concept)、“语义”(semantic)、“接口”(interface)、“服务”(service)、“职责”(responsibility)之类的名词,或“忽略”、“分离”、“提炼”、“抽取”之类的动词。而抽象的对立面,用“具体”、“具象”、“明晰”、“直观”等就不如“细节”(detail)、“实现”(implementation)等来得更贴切。


模型是抽象的结晶,而抽象成功的标志之一是形成引起共识的概念。


理想的抽象是对某一概念本质特征进行精准的捕捉和描述,不要多也不要少。多则限制该抽象的适用范围,少则不能充分利用该抽象的特性。


在某些场合下,抽象没有提供足够的信息。为了挖掘必要的信息,人们不得不钻开抽象严密封装的外壳(crust),深入到它声称能够忽略的、此时却不能忽略的内部细节,由此形成了泄露。


抽象是对付复杂的有效工具。一方面,通过抽象剔除或屏蔽非本质的部分、提炼并合并本质的部分(即《冒号课堂》中提到的减法与除法),从而降低复杂性;另一方面,通过抽象对复杂分而治之,比如,宏观上水平分层(layer),垂直分区(partition),微观上分模块、分步骤,等等。

除了复杂外,软件设计的另一大敌人是变化。当具体的代码缺失了抽象的外壳,便丧失了必要的缓冲区,一旦变化来临,难免引发代码的强烈震荡。总而言之,把抽象作为设计的出发点,不仅能更合理地组织代码,而且为代码之间划分了明确的概念边界。这种边界的划分越合理、边界的规范越明晰、边界内的代码越遵循规范,系统越稳定、越易维护。


http://blog.zhenghui.org/2011/04/18/more-words-on-abstraction/

------------------------------------------------------------------------------------------------------------------------------------------------------------------------

所以抽象(abstraction)不是vagua,而是high level;它起码要能达到实现隔离,能在更高的层次talk或者能用languange in problem domain来talk,即上文提到的concept。


### 抽象类的定义、特点及使用场景 #### 1. 抽象类的定义 抽象类是面向对象编程中一种特殊的类,它使用`abstract`关键字声明。抽象类可以包含未实现的方法(抽象方法)和已实现的方法(具体方法)。抽象类不能直接实例化,必须通过继承它的子类来创建对象[^1]。如果一个类包含至少一个抽象方法,则该类必须声明为抽象类。 ```java public abstract class AbstractClass { // 抽象方法 public abstract void abstractMethod(); // 具体方法 public void concreteMethod() { System.out.println("This is a concrete method."); } } ``` #### 2. 抽象类的特点 - **不能实例化**:抽象类不能直接创建对象,只能通过其非抽象的子类实例化对象。 - **包含抽象方法**:抽象类可以包含一个或多个没有具体实现的抽象方法。这些方法必须由子类实现。 - **部分实现**:抽象类不仅可以定义抽象方法,还可以包含具体方法和成员变量,提供通用的功能和状态[^4]。 - **强制子类实现**:任何继承抽象类的子类都必须实现所有的抽象方法,除非该子类本身也是抽象类[^1]。 - **多态支持**:抽象类为多态提供了基础,允许父类引用指向子类对象。 #### 3. 使用场景 - **通用行为定义**:当一组相关类共享某些通用行为时,可以将这些行为提取到抽象类中。例如,在一个动物模拟系统中,所有动物都有`eat`和`move`的行为,但具体的实现方式可能不同[^5]。 - **强制规范**:抽象类可以通过定义抽象方法来强制要求子类实现特定功能。例如,定义一个抽象类`Shape`,要求所有子类实现`draw`方法。 - **代码复用**:抽象类可以包含具体方法,供子类直接使用,从而减少重复代码。 ```java public abstract class Shape { public abstract void draw(); // 抽象方法 public void commonMethod() { // 具体方法 System.out.println("This is a common method for all shapes."); } } public class Circle extends Shape { @Override public void draw() { System.out.println("Drawing a circle."); } } ``` #### 面向对象编程的核心概念 - **封装**:将数据和操作数据的方法绑定在一起,并隐藏内部实现细节。抽象类通过只暴露必要的接口来实现封装[^5]。 - **继承**:抽象类是继承机制的一部分,允许子类继承父类的属性和方法,同时根据需要重写或扩展功能[^1]。 - **多态**:抽象类支持运行时多态,使得父类引用可以指向不同的子类对象,从而调用子类的具体实现[^5]。 --- ### 示例代码 以下是一个简单的抽象类示例,展示了如何定义和使用抽象类: ```java // 定义抽象类 public abstract class Vehicle { public abstract void start(); // 抽象方法 public void stop() { // 具体方法 System.out.println("Vehicle stopped."); } } // 子类实现抽象类 public class Car extends Vehicle { @Override public void start() { System.out.println("Car started."); } } public class Main { public static void main(String[] args) { Vehicle vehicle = new Car(); // 父类引用指向子类对象 vehicle.start(); // 调用子类实现的方法 vehicle.stop(); // 调用父类中的具体方法 } } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值