Java后端学习系列(2):深入面向对象与设计原则

Java后端学习系列(2):深入面向对象与设计原则

前言

在上一期我们对Java后端学习的整体路线以及基础部分做了介绍,并且进行了一些简单的代码示例展示。本期我们将深入Java后端学习中非常重要的面向对象部分,探讨其高级特性以及相关设计原则,这对于构建高质量、易维护的Java应用程序有着至关重要的作用。本系列共15期,会逐步带领大家掌握从基础到进阶的全方位知识,助力大家成为优秀的Java后端工程师。

一、封装与继承的实战应用

1.1 封装的深化理解

封装不仅仅是简单地将类的属性设置为私有并提供相应的访问器(getter和setter方法),在实际项目中,更要合理控制对内部数据的访问权限,确保数据的安全性和完整性。例如,在一个电商系统中,对于用户的订单信息类:

public class Order {
    private String orderId;
    private double totalPrice;
    private List<Product> productList;

    // 生成对应的getter和setter方法
    public String getOrderId() {
        return orderId;
    }

    public void setOrderId(String orderId) {
        this.orderId = orderId;
    }

    public double getTotalPrice() {
        return totalPrice;
    }

    // 这里设置totalPrice的修改需要经过一定的业务逻辑校验,不能随意修改
    public void setTotalPrice(double totalPrice) {
        if (totalPrice > 0) {
            this.totalPrice = totalPrice;
        }
    }

    public List<Product> getProductList() {
        return productList;
    }

    public void setProductList(List<Product> productList) {
        this.productList = productList;
    }
}

通过这样的封装,外部代码只能按照我们设定的规则来访问和修改订单信息,避免了不合理的数据操作。

1.2 继承的运用场景

继承常用于代码复用以及建立类之间的层次关系。比如我们有一个动物类作为基类,然后有不同种类的动物类去继承它,实现各自特有的行为。以下是简单示例:

// 基类动物
class Animal {
    protected String name;

    public Animal(String name) {
        this.name = name;
    }

    public void eat() {
        System.out.println(name + "正在吃东西");
    }
}

// 继承自动物类的狗类
class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }

    public void bark() {
        System.out.println(name + "正在汪汪叫");
    }
}

通过继承,Dog类复用了Animal类的eat方法,同时又添加了自己特有的bark方法,体现了继承在代码组织方面的优势。

二、多态的实现原理

2.1 多态的概念及表现形式

多态是指同一个行为具有多个不同表现形式或形态的能力。在Java中,多态主要通过方法重写(Override)和接口实现来体现。

2.2 方法重写示例

我们有一个形状类,以及它的不同子类圆形和矩形,它们都重写了计算面积的方法:

class Shape {
    public double getArea() {
        return 0;
    }
}

class Circle extends Shape {
    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    @Override
    public double getArea() {
        return Math.PI * radius * radius;
    }
}

class Rectangle extends Shape {
    private double length;
    private double width;

    public Rectangle(double length, double width) {
        this.length = length;
        this.width = width;
    }

    @Override
    public double getArea() {
        return length * width;
    }
}

通过这样的重写,当我们调用不同子类对象的getArea方法时,会根据对象实际类型执行对应的实现逻辑,体现了多态性。

2.3 接口实现多态

定义一个可绘制的接口,不同图形类实现这个接口来绘制自己:

interface Drawable {
    void draw();
}

class Triangle implements Drawable {
    @Override
    public void draw() {
        System.out.println("绘制三角形");
    }
}

class Square implements Drawable {
    @Override
    public void draw() {
        System.out.println("绘制正方形");
    }
}

这样可以将不同的图形类都当作Drawable类型来处理,根据实际对象的不同执行各自的绘制逻辑,实现多态的效果。

三、SOLID设计原则

3.1 单一职责原则(Single Responsibility Principle)

一个类应该只有一个引起它变化的原因,也就是一个类只负责一项职责。例如,一个用户登录类,就只应该处理用户登录相关的逻辑,像验证用户名密码、与数据库交互获取用户信息等,而不应该再去处理用户注册或者修改密码等其他不相关的功能。

3.2 开闭原则(Open-Closed Principle)

软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。比如我们有一个图形绘制系统,最初只支持绘制圆形,后来要增加绘制矩形的功能,我们应该通过添加新的绘制矩形类去实现接口等扩展方式来完成,而不是直接修改原来绘制圆形的代码逻辑。

3.3 里氏替换原则(Liskov Substitution Principle)

所有引用基类(父类)的地方必须能透明地使用其子类的对象。例如在上面的动物类以及其子类的例子中,如果我们有一个函数接收Animal类型参数,那么传递Dog等子类对象进去应该能够正常执行相应逻辑,不会出现不符合预期的行为。

3.4 接口隔离原则(Interface Segregation Principle)

客户端不应该被迫依赖于它不使用的方法。比如我们有一个打印机接口,有的打印机只支持黑白打印,有的支持彩色打印,那就不应该把彩色打印相关方法都放在一个通用打印机接口里强迫所有实现类都去实现,而是应该拆分出不同的接口来满足不同需求。

3.5 依赖倒置原则(Dependency Inversion Principle)

高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。例如在一个电商系统中,订单模块不应该直接依赖具体的数据库操作类,而是依赖于一个抽象的数据库访问接口,这样方便后续更换数据库实现时不用大量修改订单模块代码。

四、常用设计模式入门

4.1 单例模式

单例模式保证一个类仅有一个实例,并提供一个访问它的全局访问点。常见的实现方式有懒汉式和饿汉式:
懒汉式(线程不安全版,仅用于示例理解,实际应用需改进保证线程安全)

public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

饿汉式

public class Singleton {
    private static Singleton instance = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() {
        return instance;
    }
}

单例模式常用于一些全局配置类、数据库连接池等场景,确保在整个应用程序中只有一个实例存在。

4.2 工厂模式

简单工厂模式将对象的创建和使用分离,通过一个工厂类来创建对象。例如创建不同类型的产品对象:

// 抽象产品类
abstract class Product {
    public abstract void use();
}

// 具体产品类A
class ProductA extends Product {
    @Override
    public void use() {
        System.out.println("使用产品A");
    }
}

// 具体产品类B
class ProductB extends Product {
    @Override
    public void use() {
        System.out.println("使用产品B");
    }
}

// 工厂类
class ProductFactory {
    public static Product createProduct(String type) {
        if ("A".equals(type)) {
            return new ProductA();
        } else if ("B".equals(type)) {
            return new ProductB();
        }
        return null;
    }
}

通过工厂模式,代码的耦合性降低,当需要新增产品类型时,只需要在工厂类中做相应修改,而不用在多处使用产品的地方都去改动创建逻辑。

五、下一步学习建议

  1. 代码实践:针对上述的面向对象高级特性以及设计原则,自己动手编写一些示例代码,尝试在不同场景中运用它们,加深理解。
  2. 项目模拟:可以模拟一个小型的项目,比如图书管理系统,运用所学的面向对象知识以及设计原则来进行架构设计和代码编写,看看如何让代码更加合理、易维护。
  3. 阅读优秀代码:找一些开源的Java项目,阅读其中相关模块的代码,学习它们是如何运用这些知识来构建高质量代码的。

下期预告

《Java后端学习系列(3):Java异常处理与常用类库》

  • Java异常体系结构剖析
  • 异常处理机制与实践
  • 常用的Java类库介绍(如java.util包下的常用工具类等)
  • 日期时间处理相关类的使用

希望大家在学习过程中多思考、多实践,将这些知识真正内化为自己的技能。如果在学习中有任何疑问或者想法,欢迎在评论区交流分享,我们下期再见。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值