文章目录
- 前言
- 书籍管理系统
- 什么是过程式编程
- 面向对象编程的引入
- 什么是面向对象编程
- 面向对象编程如何解决过程式编程的问题
- 本期小知识
“面向对象编程的核心思想是‘消息传递’,这才是它的本质所在。”
前言
这里是分享 Java 相关内容的专刊,每日一更。
本期将为大家带来以下内容:
- 书籍管理系统
- 什么是过程式编程
- 面向对象编程的引入
- 什么是面向对象编程
- 面向对象编程如何解决过程式编程的问题
书籍管理系统
在编程的初期,我们常常遇到一些非常基本的需求。假设我们正在开发一个简单的书籍管理系统,目标是让用户能够添加、查看和删除书籍。例如:
java">import java.util.ArrayList;
import java.util.Scanner;
public class BookManager {
// 静态变量 books 用于存储书籍列表
// 因为是 static,所有 BookManager 类的实例都会共享这一个列表
static ArrayList<String> books = new ArrayList<>();
// 添加书籍的方法,接收书名并将其添加到 books 列表中
public static void addBook(String book) {
books.add(book);
}
// 显示所有书籍的方法,遍历 books 列表并打印出每个书名
public static void displayBooks() {
// 使用增强型 for 循环遍历每本书
for (String book : books) {
System.out.println(book);
}
}
// 删除书籍的方法,根据书名将其从 books 列表中移除
public static void removeBook(String book) {
books.remove(book); // 按书名删除,如果存在多个同名书籍,只会删除第一个找到的
}
// 主程序,负责用户输入及系统操作
public static void main(String[] args) {
// Scanner 对象用于读取用户输入
Scanner scanner = new Scanner(System.in);
// 用于控制菜单循环的布尔变量
boolean running = true;
// 使用 while 循环不断显示菜单并响应用户输入,直到用户选择退出
while (running) {
// 显示菜单选项
System.out.println("1. 添加书籍");
System.out.println("2. 查看书籍");
System.out.println("3. 删除书籍");
System.out.println("4. 退出");
// 读取用户的选择(1-4),并确保读取换行符以避免下一次输入问题
int choice = scanner.nextInt();
scanner.nextLine(); // 读取换行符,避免与下一次输入冲突
// 根据用户的选择执行不同操作
switch (choice) {
case 1:
// 选择添加书籍,提示用户输入书籍名称
System.out.print("输入书籍名称: ");
String book = scanner.nextLine(); // 读取书籍名称
addBook(book); // 调用 addBook 方法将书籍添加到列表
break;
case 2:
// 选择查看书籍,调用 displayBooks 方法展示书籍列表
displayBooks();
break;
case 3:
// 选择删除书籍,提示用户输入要删除的书名
System.out.print("输入要删除的书籍名称: ");
String bookToRemove = scanner.nextLine(); // 读取书籍名称
removeBook(bookToRemove); // 调用 removeBook 方法删除书籍
break;
case 4:
// 选择退出程序,将 running 设置为 false 以结束循环
running = false;
break;
default:
// 输入无效的选择时,提示用户重新选择
System.out.println("无效选择");
}
}
// 关闭 Scanner 对象以释放资源
scanner.close();
}
}
上面的代码是可以运行的,并且能够完成书籍的添加、删除和显示功能。然而,随着功能的增加和系统复杂度的提升,这种实现很快会暴露出以下问题:
- 全局状态问题:
books
作为全局变量,如果系统变得复杂,容易引入难以发现的 bug,任何函数都可以修改书籍列表,程序的行为变得不可预测。 - 扩展性差:如果我们想要为书籍添加更多的属性,比如作者、ISBN、出版日期等,修改代码的难度会急剧增加。
- 代码可读性差:随着功能越来越多,
main()
方法会变得非常复杂,难以维护。 - 无组织性:所有的功能都在一个类中,代码结构松散,职责不清,违背了单一职责原则。
这些问题表明,虽然程序是可以工作的,但它很快会变得难以维护和扩展。这里我们看到的编程风格被称为 过程式编程。
什么是过程式编程
过程式编程(Procedural Programming)是一种传统的编程范式,它通过函数(或过程)的调用来解决问题。程序的执行是通过依次调用不同的函数,处理数据和执行特定的逻辑任务。
过程式编程的几个特点:
- 数据与函数分离:数据和操作数据的函数是分开的,数据通常以全局变量的形式存在,函数是操作数据的过程。
- 线性流程:程序主要通过函数调用形成一系列的步骤或流程来完成任务。
- 重复代码较多:过程式编程常常会导致重复代码,因为每个函数都只处理特定的数据集。
虽然这种编程范式在处理小型程序时比较有效,但随着程序规模的扩大,它的局限性会越来越明显。
面向对象编程的引入
为了更好地组织代码,解决过程式编程中的种种问题,程序设计逐渐引入了 面向对象编程(Object-Oriented Programming, OOP)。
面向对象编程的核心思想是将数据与操作这些数据的函数封装到一个对象中,通过对现实世界中对象的模拟,简化复杂系统的设计与开发。
什么是面向对象编程
面向对象编程 是一种编程范式,强调通过对象来组织程序代码。对象既包含数据(属性),也包含操作这些数据的行为(方法)。通过对象间的交互来实现程序的功能。
OOP 的四大基本特性(一般常说的只有前 3 个):
- 封装:将数据和操作数据的方法封装在一个对象中,防止外部直接访问数据,确保数据安全性和完整性。
- 继承:允许一个类从另一个类继承属性和方法,从而实现代码复用。
- 多态:不同的对象可以以相同的方式进行交互,但它们可以表现出不同的行为。
- 抽象:将不重要的细节隐藏,关注对象的核心功能。
面向对象编程如何解决过程式编程的问题
为了展示 OOP 如何解决上述书籍管理系统中的问题,我们可以重新设计书籍管理系统,使用面向对象的方法。
java">// 书籍类,表示系统中的书籍对象,封装书籍的相关属性和行为
class Book {
// 私有字段 title,封装书籍的名称,只能通过方法访问
private String title;
// 构造函数,用于创建书籍对象时初始化书籍名称
public Book(String title) {
this.title = title;
}
// 获取书籍名称的方法,提供对私有字段 title 的读取权限
public String getTitle() {
return title;
}
// 重写 toString 方法,当打印书籍对象时显示更易读的输出信息
@Override
public String toString() {
return "Book: " + title;
}
}
java">// 书籍管理类,负责管理书籍的添加、显示和删除等操作
class BookManager {
// 私有的 books 集合,存储所有添加的书籍对象
private ArrayList<Book> books = new ArrayList<>();
// 添加书籍的方法,将输入的书名封装成 Book 对象,并添加到 books 列表
public void addBook(String title) {
books.add(new Book(title));
}
// 显示所有书籍的方法,遍历 books 列表并打印每本书的信息
public void displayBooks() {
for (Book book : books) {
System.out.println(book); // 调用 Book 类的 toString() 方法
}
}
// 删除书籍的方法,根据书名匹配并从 books 列表中删除对应的书籍
public void removeBook(String title) {
books.removeIf(book -> book.getTitle().equals(title));
// 使用 Lambda 表达式,根据书名匹配并删除符合条件的书籍
}
}
java">// 主类,负责程序的启动,提供简单的控制台交互界面
public class Main {
public static void main(String[] args) {
// 创建一个 Scanner 对象,用于读取用户输入
Scanner scanner = new Scanner(System.in);
// 创建 BookManager 对象,用于管理书籍
BookManager bookManager = new BookManager();
// 控制程序运行的布尔变量
boolean running = true;
// 进入主循环,提供菜单供用户选择操作
while (running) {
// 打印菜单选项
System.out.println("1. 添加书籍");
System.out.println("2. 查看书籍");
System.out.println("3. 删除书籍");
System.out.println("4. 退出");
// 读取用户的菜单选择
int choice = scanner.nextInt();
scanner.nextLine(); // 读取换行符,避免输入错误
// 根据用户选择执行不同的操作
switch (choice) {
case 1:
// 添加书籍操作
System.out.print("输入书籍名称: ");
String title = scanner.nextLine(); // 获取用户输入的书名
bookManager.addBook(title); // 调用 BookManager 添加书籍
break;
case 2:
// 查看所有书籍操作
bookManager.displayBooks(); // 调用 BookManager 显示所有书籍
break;
case 3:
// 删除书籍操作
System.out.print("输入要删除的书籍名称: ");
String bookToRemove = scanner.nextLine(); // 获取用户输入的要删除的书名
bookManager.removeBook(bookToRemove); // 调用 BookManager 删除书籍
break;
case 4:
// 退出程序
running = false; // 设置 running 为 false,终止循环
break;
default:
// 用户输入无效选项时提示
System.out.println("无效选择");
}
}
// 关闭 Scanner 对象,释放资源
scanner.close();
}
}
面向对象编程的优势:
- 数据封装:通过
Book
类封装书籍的相关信息,书籍数据不再以全局变量的形式存在,提升了数据的安全性和模块化。 - 扩展性好:如果需要为书籍添加更多属性,例如作者或出版日期,只需修改
Book
类,而不需要大范围更改代码。 - 职责明确:
Book
类负责存储书籍信息,BookManager
类负责管理书籍集合,代码的职责划分清晰,符合单一职责原则。 - 易于维护:通过将相关逻辑封装在类中,面向对象编程使得代码结构更清晰,便于维护和扩展。
本期小知识
在 Java 面世之前,面向对象编程已经通过 C++ 等语言流行开来,但 C++ 的复杂性让很多开发者头痛不已。Java 的设计者们下决心简化 OOP,使得更多开发者可以轻松上手。因此,Java 被设计为一个去掉了复杂功能(如多重继承、手动内存管理)的语言,并且通过引入接口、抽象类等概念,让面向对象编程变得更加实用和直观。这使得 Java 成为许多开发者入门 OOP 的首选语言。