博客
关于我
Java 面向对象编程的四个基本原则(封装、继承、多态和抽象),并给出一个简单的例子说明如何在 Java 中应用这些原则?
阅读量:807 次
发布时间:2023-01-27

本文共 4745 字,大约阅读时间需要 15 分钟。

面向对象编程(OOP)是Java编程中的核心概念,它通过对象的划分实现代码的模块化和可维护性。四大基本原则——封装、继承、多态和抽象——是OOP的基石,每个原则都为开发者构建更高效的代码提供了有效的手段。

封装是开发者在对象化编程中首先学习的概念。它指通过将数据和行为捆绑在一起,保护对象的内部实现细节。对 Java 开发者来说,最直观的封装方式是通过字段声明为 private,并通过 setter 和 getter 方法进行访问。例如,银行账户类 BankAccount 中的 balance 字段被声明为 private,外部只能通过 getBalance() 方法获取,这样既保留了控制权,又确保了代码的安全性。

Justice Bank account 类的一个很好的示例是这样的:

public class BankAccount {    private double balance;    public BankAccount(double initialBalance) {        if (initialBalance > 0.0) {            balance = initialBalance;        } else {            throw new IllegalArgumentException("Initial balance must be greater than zero.");        }    }    public double getBalance() {        return balance;    }    public void deposit(double amount) {        if (amount > 0.0) {            balance += amount;        } else {            throw new IllegalArgumentException("Deposit amount must be positive.");        }    }    public void withdraw(double amount) {        if (amount > 0.0 && amount <= balance) {            balance -= amount;        } else {            throw new IllegalArgumentException("Withdrawal amount must be positive and less than or equal to the balance.");        }    }}

通过将 balance 属性私有化并提供公有方法,实现了对账户内部状态的控制。这种封装方法不仅保持代码的安全性,还允许我们在必要时添加各种校验逻辑。

继承则是在OOP中进一步强化代码复用性的一个重要概念。它允许一个子类继承父类的属性和方法,从而避免重复编写代码。比如,SavingsAccount 类可以继承 BankAccount 的大部分功能,并添加互利计算的方法。这种继承方式使得代码结构层次分明,易于扩展和维护。

对于继承的示例,我们可以创建一个扩展 BankAccount 的 SavingsAccount 类:

public class SavingsAccount extends BankAccount {    private double interestRate;    public SavingsAccount(double initialBalance, double interestRate) {        super(initialBalance);        this.interestRate = interestRate;    }    public void addInterest() {        double interest = getBalance() * interestRate;        deposit(interest);    }}

通过这种继承方式,我们不仅复用了父类的方法,还确保了子类的唯一性和功能特异性。

多态的概念与继承结合使用时特别有用。它允许一个对象以多种形式表现出不同的行为。例如,在 BankAccount 类中定义一个 abstract 方法 calculateInterest(),然后由具体的子类如 SavingsAccount 实现。这使得我们能够在不关心具体实现的情况下,统一处理所有类型的账户。

对于多态的实现,可以考虑如下代码:

public abstract class BankAccount {    private double balance;    public BankAccount(double initialBalance) {        if (initialBalance > 0.0) {            balance = initialBalance;        } else {            throw new IllegalArgumentException("Initial balance must be greater than zero.");        }    }    public double getBalance() {        return balance;    }    public void deposit(double amount) {        if (amount > 0.0) {            balance += amount;        } else {            throw new IllegalArgumentException("Deposit amount must be positive.");        }    }    public void withdraw(double amount) {        if (amount > 0.0 && amount <= balance) {            balance -= amount;        } else {            throw new IllegalArgumentException("Withdrawal amount must be positive and less than or equal to the balance.");        }    }    public abstract double calculateInterest();}

然后,SavingsAccount 类可以实现这个方法:

public class SavingsAccount extends BankAccount {    private double interestRate;    public SavingsAccount(double initialBalance, double interestRate) {        super(initialBalance);        this.interestRate = interestRate;    }    @Override    public double calculateInterest() {        return getBalance() * interestRate;    }}

这样,在同一个方法中,可以支持多种类型的账户,这就是多态的力量所在。

抽象类或接口是实现多态和抽象概念的重要手段。通过定义一组通用行为,我们可以让不同类型的对象遵循相同的接口。例如,Account 接口定义了基本的存取行为,而 BankAccount 和 SavingsAccount 类都实现这个接口。这样一来,我们可以在不关心具体实现的情况下,写出通用的代码。

一个最好的方法是创建一个Account 接口:

public interface Account {    void deposit(double amount);    void withdraw(double amount);    double getBalance();}

然后,具体的 BankAccount 类实现它:

public class BankAccount implements Account {    private double balance;    public BankAccount(double initialBalance) {        if (initialBalance > 0.0) {            balance = initialBalance;        } else {            throw new IllegalArgumentException("Initial balance must be greater than zero.");        }    }    public void deposit(double amount) {        if (amount > 0.0) {            balance += amount;        } else {            throw new IllegalArgumentException("Deposit amount must be positive.");        }    }    public void withdraw(double amount) {        if (amount > 0.0 && amount <= balance) {            balance -= amount;        } else {            throw new IllegalArgumentException("Withdrawal amount must be positive and less than or equal to the balance.");        }    }    public double getBalance() {        return balance;    }}

通过这种方式,所有账户类型都遵循相同的接口,从而可以在一个通用的方法中处理它们的行为。

Developers 的最佳实践可以总结为:

  • 封装:尽量将字段设为 private,并通过 getter 和 setter 方法提供必要的访问点,并在 setter 中添加必要的验证逻辑。
  • 继承:仅用于共享行为和状态的类之间,避免过度继承导致代码混乱。
  • 多态:利用抽象类或接口定义通用行为,并在子类中定制实现。
  • 抽象:使用抽象类或接口来定义通用行为规范,确保代码的扩展性。
  • 在实际开发中,需注意避免过度封装、过度继承,避免接口过于庞大,和避免为了抽象而抽象。

    转载地址:http://tfryk.baihongyu.com/

    你可能感兴趣的文章
    nacos服务注册和发现原理简单实现案例
    查看>>
    Nacos服务注册总流程(源码分析)
    查看>>
    nacos服务注册流程
    查看>>
    Nacos服务部署安装
    查看>>
    nacos本地可以,上服务器报错
    查看>>
    Nacos注册Dubbo(2.7.x)以及namespace配置
    查看>>
    Nacos注册中心有几种调用方式?
    查看>>
    nacos注册失败,Feign调用失败,feign无法注入成我们的bean对象
    查看>>
    nacos源码 nacos注册中心1.4.x 源码 nacos源码如何下载 nacos 客户端源码下载地址 nacos discovery下载地址(一)
    查看>>
    nacos源码 nacos注册中心1.4.x 源码 spring cloud alibaba 的discovery做了什么 nacos客户端是如何启动的(二)
    查看>>
    nacos源码 nacos注册中心1.4.x 源码 如何注册服务 发送请求,nacos clinet客户端心跳 nacos 注册中心客户端如何发送的心跳 (三)
    查看>>
    Nacos源码分析:心跳机制、健康检查、服务发现、AP集群
    查看>>
    nacos看这一篇文章就够了
    查看>>
    Nacos简介、下载与配置持久化到Mysql
    查看>>
    Nacos简介和控制台服务安装
    查看>>
    Nacos管理界面详细介绍
    查看>>
    Nacos编译报错NacosException: endpoint is blank
    查看>>
    nacos自动刷新配置
    查看>>
    nacos运行报错问题之一
    查看>>
    Nacos部署中的一些常见问题汇总
    查看>>