封装、继承、多态的含义及其项目应用

一、封装

1.含义

具体来说,封装就是将属性和操作方法捆绑在一起,形成一个独立的"类",并通过访问控制(如private、public 等修饰符)限制外部对内部的直接操作,只允许通过预先定义来访问或修改数据

其核心思想是:"隐藏内部细节,暴露必要接口"。

2.目的

(1)保护数据安全性,防止外部随意修改内部数据,避免数据被错误篡改

(2)降低耦合度:外部只需用就行,不用关注内部是如何实现的,即使用时,即使封装类内部逻辑发生了变化,只要接口不变,外部代码就无需改变

(3)提高代码可维护性:内部逻辑集中在类中,修改时只需要调整类的内部,不影响外部使用

3.在项目的应用场景:

(1)实体类(Form/VO)的封装

当我们写项目时,接口文档中显示着需要我们接受或者返回的参数,这些参数

示例:

php 复制代码
### 人脸采集

URL

```
POST /sys/person/addPerson
```

参数

```
{
    "personId": 98,
    "extName": "png",
    "fileBase64": "iVBORw0KGgoAAAANSUhEUgAAAJsAAAC4CAYAAAD0WZ4UAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJ8pt02jBn6wUmcy/39/xgi2nSFeQGzAAAAAElFTkSuQmCC"
}
```

返回

```
{
    "msg": "操作成功",
    "code": 200
}
```

### 删

这是完成人脸采集的接口内容,我们可以看到要从前端接受的参数为:

php 复制代码
"personId": 98,
    "extName": "png",
    "fileBase64": "iVBORw0KGgoAAAANSUhEUgAAAJsAAAC4CAYAAAD0WZ4UAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJ8pt02jBn6wUmcy/39/xgi2nSFeQGzAAAAAElFTkSuQmCC"

但是我们的我们对应的项目根本没有对应的实体类,此时我们就可以封装一个新的实体类FORM

java 复制代码
package com.qcby.model.entity;


import lombok.Data;

@Data
public class FaceForm {
    private Integer personId;
    private String extName;
    private String fileBase64;
}

注:@Data注解已经完成了 set和get方法

应用价值:

当数据传过来时 我们可以用Data注解中的set方法设置创建类的属性的值,这样的封装类应用起来既方便又安全,不用我们在外部一个一个设置属性了。

(2)工具类的封装

将通用功能(如日期处理、加密处理)封装成工具类,隐藏实现细节,只是暴露静态方法供外部调用。

示例:

java 复制代码
public class DateUtils {
    // 私有构造方法,禁止外部创建实例(工具类无需实例化)
    private DateUtils() {}

    // 公开静态方法(暴露接口)
    public static String format(Date date, String pattern) {
        // 内部实现(隐藏细节,比如用 SimpleDateFormat 处理)
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(date);
    }

    public static Date parse(String dateStr, String pattern) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.parse(dateStr);
    }
}

应用价值:

(1)外部只需要调用 DateUtils.format(...)即可格式化日期,无需关心SimpleDateFormat的用法和线程安全问题

(2)如果未来想替换为DateTimeFormatter,只需要修改工具类内部,外部调用代码无需变动。

(3)服务层的封装

在分层架构中(SpringBoot)中,Service层封装业务逻辑,隐藏复杂的处理流程对外提供简洁的接口。

示例:

在业务层实现动态路由业务逻辑:

java 复制代码
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, MenuEntity> implements MenuService {  
  @Autowired
    MenuMapper menuMapper;

     @Override
    public List<MenuRouterVO> getMenuRouterVOById(Integer UserId) {
        List<MenuEntity> menulist = menuMapper.getMenuById(UserId);
        return getMenuRouterVOList(menulist);
    }
     private List<MenuRouterVO> getMenuRouterVOList(List<MenuEntity> menulist) {
        //创建一个大的集合是为了能封装最后的数据

        List<MenuRouterVO> menuRouterVOList = new ArrayList<>();
        for (MenuEntity menu : menulist) {
            if (menu.getParentId() == 0) {

                //再创建一个新的MenuRouterVO类
                MenuRouterVO menuRouterVO = new MenuRouterVO();
                //将parent_id为0的菜单信息(父级菜单对象)赋值
                BeanUtils.copyProperties(menu, menuRouterVO);

                //再赋值剩下的部分
                MetaVo metaVo = new MetaVo();
                metaVo.setTitle(menu.getName());
                metaVo.setIcon(menu.getIcon());
                menuRouterVO.setMeta(metaVo);
                //Menu和Menuvo都装好了,现在我们去寻找父级菜单的孩子属性
                List<ChildrenMenuRouterVO> children = new ArrayList<>();

                for (MenuEntity child : menulist) {
                    if (child.getParentId() == menu.getMenuId()) {
                        ChildrenMenuRouterVO childMenuRouterVO = new ChildrenMenuRouterVO();
                        BeanUtils.copyProperties(child, childMenuRouterVO);
                        childMenuRouterVO.setMeta(metaVo);
                        MetaVo metaVo1 = new MetaVo();
                        metaVo1.setTitle(child.getName());
                        metaVo1.setIcon(child.getIcon());
                        childMenuRouterVO.setMeta(metaVo1);
                        children.add(childMenuRouterVO);
                    }
                }
                menuRouterVO.setChildren(children);
                menuRouterVOList.add(menuRouterVO);
            }

        }
        return menuRouterVOList;
    }
}

应用价值:

封装好之后我们只需要在表现层(Controller层) 引入MenuService类属性

java 复制代码
@Autowired

private MenuService menuService

再 调用menuService.getMenuRouterVOById(Integer UserId)方法就可以得到相应的数据

二、继承

1.核心思想

继承的核心思想是:"复用已有类的属性和方法,并在此基础上扩展新功能"

2.核心目的:

(1)代码复用:避免重复编写相同的代码(父类定义通用逻辑,子类直接复用)

(2)逻辑扩展:再父类基础上添加新功能,实现"特殊化"。

(3)多态基础:子类对象可以被当作父类对象使用,为多态(同一操作在不同对象有不同表现)提供支持

3.在项目的应用场景:

(1)提取通用逻辑,减少重复代码

当多个类存在相同的属性或方法时,将这些共性提取到父类中,子类继承父类即可复用,无需重复编写。

示例:

在电商系统中,"商品"可分为"实体商品"(如手机)和"虚拟商品"(如充值卡),它们有共性(名称、价格、库存),也有差异(实体商品有重量,虚拟商品有有效期)。

java 复制代码
//提取共性
public class Product{

  //protected 保证子类可以访问
  protected String name;//商品名称
  protected Double price;//价格
  protected int stock;//库存 

//共性方法:计算总价
  public double calculateTotal(int quantity){
     return price*quantity;
  }
  
  //其他共性方法(如设置名称、获取价格等)
  public void setName (String name){this.name=name;}
  public double getPrice(){return price;}

}
// 子类1:实体商品(继承父类,添加特有属性)
public class PhysicalProduct extends Product {
    private double weight; // 特有属性:重量

    // 特有方法:计算运费
    public double calculateShippingFee() {
        return weight * 0.5; // 假设每公斤0.5元运费
    }
}

// 子类2:虚拟商品(继承父类,添加特有属性)
public class VirtualProduct extends Product {
    private String expiryDate; // 特有属性:有效期

    // 特有方法:检查是否过期
    public boolean isExpired() {
        // 实现过期检查逻辑
        return false;
    }
}

应用价值

(1) 父类 Product 定义了所有商品的共性,子类无需重复编写 nameprice 等属性 和 calculateTotal 方法。

(2)子类专注于自己的特有逻辑(如 PhysicalProduct 的运费计算),代码更简洁。

(2) 实现 "多态",简化代码逻辑

继承允许子类对象被当作父类对象使用,从而可以用统一的方式处理不同子类的实例,减少代码分支。

示例

在支付系统中,有多种支付方式(微信支付、支付宝支付),它们都需要 "发起支付" 和 "查询支付结果" 的功能,但实现细节不同。

java 复制代码
// 父类:定义支付的通用接口
public abstract class Payment {
    // 抽象方法:子类必须实现具体逻辑
    public abstract void pay(double amount);
    public abstract String queryStatus(String orderId);
}

// 子类1:微信支付
public class WechatPayment extends Payment {
    @Override
    public void pay(double amount) {
        System.out.println("微信支付:" + amount + "元");
        // 微信支付的具体实现(调用微信接口等)
    }

    @Override
    public String queryStatus(String orderId) {
        return "微信支付状态:已支付"; // 模拟查询结果
    }
}

// 子类2:支付宝支付
public class AlipayPayment extends Payment {
    @Override
    public void pay(double amount) {
        System.out.println("支付宝支付:" + amount + "元");
        // 支付宝支付的具体实现
    }

    @Override
    public String queryStatus(String orderId) {
        return "支付宝支付状态:已支付"; // 模拟查询结果
    }
}

(3).使用时的多态场景

java 复制代码
public class PaymentService {
    // 统一处理支付:参数为父类类型,可接收任何子类对象
    public void processPayment(Payment payment, double amount) {
        payment.pay(amount); // 调用的是子类的具体实现
    }
}

// 测试
public class Test {
    public static void main(String[] args) {
        PaymentService service = new PaymentService();
        
        // 传入微信支付对象
        service.processPayment(new WechatPayment(), 100); 
        // 传入支付宝支付对象
        service.processPayment(new AlipayPayment(), 200); 
    }
}

三、多态

多态的核心思想:"同一操作作用于不同对象时,产生不同的执行结果"

1.多态的实现条件

在java中,多态的实现需要满足三个条件:

(1)继承关系:子类必须继承父类(或实现接口);

(2)方法重写:子类重写(@Override)父类的方法;

(3)父类引用指向子类对象:如Parent p = new Child();

2.多态的核心目的:

(1).简化代码逻辑:用统一的方式处理不同类型的对象,减少分支判断(if-else/switch);

(2)提升扩展性:新增子类时,无需修改现有的代码,只需新增实现(符合"开闭原则");

(3)解耦:调用者只需关注父类接口,无需知道具体子类的实现细节。

3.在项目的应用场景

(1). 统一接口,不同实现(以支付系统为例)

在支付场景中,无论用户选择微信、支付宝还是银联支付,系统的核心流程都是 "发起支付",但不同支付方式的底层实现不同。

java 复制代码
// 1. 定义父接口(或抽象类):统一支付行为
public interface Payment {
    void pay(double amount); // 抽象方法:支付
}

// 2. 子类实现:不同支付方式
public class WechatPayment implements Payment {
    @Override
    public void pay(double amount) {
        System.out.println("微信支付:" + amount + "元(调用微信接口)");
    }
}

public class AlipayPayment implements Payment {
    @Override
    public void pay(double amount) {
        System.out.println("支付宝支付:" + amount + "元(调用支付宝接口)");
    }
}

// 3. 调用者:依赖父接口,不关心具体实现
public class OrderService {
    // 统一支付入口:参数为Payment接口,可接收任何实现类
    public void processPayment(Payment payment, double amount) {
        payment.pay(amount); // 多态:实际执行子类的pay方法
    }
}

// 测试
public class Test {
    public static void main(String[] args) {
        OrderService service = new OrderService();
        
        // 父接口引用指向不同子类对象
        Payment wechat = new WechatPayment();
        Payment alipay = new AlipayPayment();
        
        // 调用同一方法,执行不同实现
        service.processPayment(wechat, 100); // 微信支付:100元
        service.processPayment(alipay, 200); // 支付宝支付:200元
    }
}
(2)集合框架中的多态(Java标准库应用)

Java集合框架大量使用多态,比如List接口有ArrayList 、LinkedList等实现类:

java 复制代码
// 父接口引用指向子类对象
List<String> list1 = new ArrayList<>(); 
List<String> list2 = new LinkedList<>();

// 调用同一方法(add),执行不同实现
list1.add("a"); // ArrayList的add(数组扩容逻辑)
list2.add("b"); // LinkedList的add(链表节点插入逻辑)
(3)框架中的多态(以SpringMVC为例)
在SpringMVC中,Controller处理请求的方式不同,但框架通过多态统一调度:
java 复制代码
// 父类/接口:Spring定义的处理器接口
public interface HandlerAdapter {
    boolean supports(Object handler); // 判断是否支持该处理器
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}

// 子类实现:不同类型的处理器适配器
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
    @Override
    public boolean supports(Object handler) {
        return handler instanceof Controller; // 支持传统Controller
    }
    
    @Override
    public ModelAndView handle(...) {
        // 处理传统Controller的请求
    }
}

public class RequestMappingHandlerAdapter implements HandlerAdapter {
    @Override
    public boolean supports(Object handler) {
        return handler instanceof HandlerMethod; // 支持@Controller注解的处理器
    }
    
    @Override
    public ModelAndView handle(...) {
        // 处理注解式Controller的请求
    }
}
(4)策略模式(多态的经典设计模式)

策略模式是多态的典型应用,用于封装一组可替换的算法。例如,电商系统的折扣策略(新用户折扣、会员折扣、节日折扣):

java 复制代码
// 1. 策略接口(父类)
public interface DiscountStrategy {
    double calculateDiscount(double price); // 计算折扣后价格
}

// 2. 具体策略(子类)
public class NewUserDiscount implements DiscountStrategy {
    @Override
    public double calculateDiscount(double price) {
        return price * 0.8; // 新用户8折
    }
}

public class MemberDiscount implements DiscountStrategy {
    @Override
    public double calculateDiscount(double price) {
        return price * 0.7; // 会员7折
    }
}

// 3. 使用策略的上下文类
public class OrderCalculator {
    private DiscountStrategy strategy;

    // 动态设置策略(多态:接收任何策略实现)
    public void setStrategy(DiscountStrategy strategy) {
        this.strategy = strategy;
    }

    public double calculateFinalPrice(double price) {
        return strategy.calculateDiscount(price); // 执行当前策略
    }
}

// 测试
public class Test {
    public static void main(String[] args) {
        OrderCalculator calculator = new OrderCalculator();
        
        // 动态切换策略
        calculator.setStrategy(new NewUserDiscount());
        System.out.println(calculator.calculateFinalPrice(100)); // 80.0
        
        calculator.setStrategy(new MemberDiscount());
        System.out.println(calculator.calculateFinalPrice(100)); // 70.0
    }
}

(5)多态的注意事项

  1. 编译时类型与运行时类型:父类引用的编译时类型是父类,运行时类型是子类(如 Payment p = new WechatPayment() 中,编译时 pPayment 类型,运行时是 WechatPayment 类型);
  2. 方法调用规则:多态仅针对 "实例方法",静态方法、字段不支持多态(调用时取决于编译时类型);
  3. 向上转型与向下转型:
    • 向上转型(自动):Parent p = new Child();(安全,多态的基础);
    • 向下转型(强制):Child c = (Child)p;(需用 instanceof 检查,否则可能抛 ClassCastException)。