封装、继承、多态的含义及其项目应用
一、封装
1.含义
具体来说,封装就是将属性和操作方法捆绑在一起,形成一个独立的"类",并通过访问控制(如private、public 等修饰符)限制外部对内部的直接操作,只允许通过预先定义来访问或修改数据
其核心思想是:"隐藏内部细节,暴露必要接口”。
2.目的
(1)保护数据安全性,防止外部随意修改内部数据,避免数据被错误篡改
(2)降低耦合度:外部只需用就行,不用关注内部是如何实现的,即使用时,即使封装类内部逻辑发生了变化,只要接口不变,外部代码就无需改变
(3)提高代码可维护性:内部逻辑集中在类中,修改时只需要调整类的内部,不影响外部使用
3.在项目的应用场景:
(1)实体类(Form/VO)的封装
当我们写项目时,接口文档中显示着需要我们接受或者返回的参数,这些参数
示例:
### 人脸采集URL```
POST /sys/person/addPerson
```参数```
{"personId": 98,"extName": "png","fileBase64": "iVBORw0KGgoAAAANSUhEUgAAAJsAAAC4CAYAAAD0WZ4UAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJ8pt02jBn6wUmcy/39/xgi2nSFeQGzAAAAAElFTkSuQmCC"
}
```返回```
{"msg": "操作成功","code": 200
}
```### 删
这是完成人脸采集的接口内容,我们可以看到要从前端接受的参数为:
"personId": 98,"extName": "png","fileBase64": "iVBORw0KGgoAAAANSUhEUgAAAJsAAAC4CAYAAAD0WZ4UAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJ8pt02jBn6wUmcy/39/xgi2nSFeQGzAAAAAElFTkSuQmCC"
但是我们的我们对应的项目根本没有对应的实体类,此时我们就可以封装一个新的实体类FORM
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)工具类的封装
将通用功能(如日期处理、加密处理)封装成工具类,隐藏实现细节,只是暴露静态方法供外部调用。
示例:
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层封装业务逻辑,隐藏复杂的处理流程对外提供简洁的接口。
示例:
在业务层实现动态路由业务逻辑:
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, MenuEntity> implements MenuService { @AutowiredMenuMapper menuMapper;@Overridepublic 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类属性
@Autowiredprivate MenuService menuService
再 调用menuService.getMenuRouterVOById(Integer UserId)方法就可以得到相应的数据
二、继承
1.核心思想
继承的核心思想是:"复用已有类的属性和方法,并在此基础上扩展新功能”
2.核心目的:
(1)代码复用:避免重复编写相同的代码(父类定义通用逻辑,子类直接复用)
(2)逻辑扩展:再父类基础上添加新功能,实现"特殊化"。
(3)多态基础:子类对象可以被当作父类对象使用,为多态(同一操作在不同对象有不同表现)提供支持
3.在项目的应用场景:
(1)提取通用逻辑,减少重复代码
当多个类存在相同的属性或方法时,将这些共性提取到父类中,子类继承父类即可复用,无需重复编写。
示例:
在电商系统中,"商品"可分为"实体商品"(如手机)和"虚拟商品"(如充值卡),它们有共性(名称、价格、库存),也有差异(实体商品有重量,虚拟商品有有效期)。
//提取共性
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
定义了所有商品的共性,子类无需重复编写 name
、price
等属性 和 calculateTotal
方法。
(2)子类专注于自己的特有逻辑(如 PhysicalProduct
的运费计算),代码更简洁。
(2) 实现 “多态”,简化代码逻辑
继承允许子类对象被当作父类对象使用,从而可以用统一的方式处理不同子类的实例,减少代码分支。
示例:
在支付系统中,有多种支付方式(微信支付、支付宝支付),它们都需要 “发起支付” 和 “查询支付结果” 的功能,但实现细节不同。
// 父类:定义支付的通用接口
public abstract class Payment {// 抽象方法:子类必须实现具体逻辑public abstract void pay(double amount);public abstract String queryStatus(String orderId);
}// 子类1:微信支付
public class WechatPayment extends Payment {@Overridepublic void pay(double amount) {System.out.println("微信支付:" + amount + "元");// 微信支付的具体实现(调用微信接口等)}@Overridepublic String queryStatus(String orderId) {return "微信支付状态:已支付"; // 模拟查询结果}
}// 子类2:支付宝支付
public class AlipayPayment extends Payment {@Overridepublic void pay(double amount) {System.out.println("支付宝支付:" + amount + "元");// 支付宝支付的具体实现}@Overridepublic String queryStatus(String orderId) {return "支付宝支付状态:已支付"; // 模拟查询结果}
}
(3).使用时的多态场景
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). 统一接口,不同实现(以支付系统为例)
在支付场景中,无论用户选择微信、支付宝还是银联支付,系统的核心流程都是 “发起支付”,但不同支付方式的底层实现不同。
// 1. 定义父接口(或抽象类):统一支付行为
public interface Payment {void pay(double amount); // 抽象方法:支付
}// 2. 子类实现:不同支付方式
public class WechatPayment implements Payment {@Overridepublic void pay(double amount) {System.out.println("微信支付:" + amount + "元(调用微信接口)");}
}public class AlipayPayment implements Payment {@Overridepublic 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等实现类:
// 父接口引用指向子类对象
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处理请求的方式不同,但框架通过多态统一调度:
// 父类/接口:Spring定义的处理器接口
public interface HandlerAdapter {boolean supports(Object handler); // 判断是否支持该处理器ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}// 子类实现:不同类型的处理器适配器
public class SimpleControllerHandlerAdapter implements HandlerAdapter {@Overridepublic boolean supports(Object handler) {return handler instanceof Controller; // 支持传统Controller}@Overridepublic ModelAndView handle(...) {// 处理传统Controller的请求}
}public class RequestMappingHandlerAdapter implements HandlerAdapter {@Overridepublic boolean supports(Object handler) {return handler instanceof HandlerMethod; // 支持@Controller注解的处理器}@Overridepublic ModelAndView handle(...) {// 处理注解式Controller的请求}
}
(4)策略模式(多态的经典设计模式)
策略模式是多态的典型应用,用于封装一组可替换的算法。例如,电商系统的折扣策略(新用户折扣、会员折扣、节日折扣):
// 1. 策略接口(父类)
public interface DiscountStrategy {double calculateDiscount(double price); // 计算折扣后价格
}// 2. 具体策略(子类)
public class NewUserDiscount implements DiscountStrategy {@Overridepublic double calculateDiscount(double price) {return price * 0.8; // 新用户8折}
}public class MemberDiscount implements DiscountStrategy {@Overridepublic 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.0calculator.setStrategy(new MemberDiscount());System.out.println(calculator.calculateFinalPrice(100)); // 70.0}
}
(5)多态的注意事项
- 编译时类型与运行时类型:父类引用的编译时类型是父类,运行时类型是子类(如
Payment p = new WechatPayment()
中,编译时p
是Payment
类型,运行时是WechatPayment
类型); - 方法调用规则:多态仅针对 “实例方法”,静态方法、字段不支持多态(调用时取决于编译时类型);
- 向上转型与向下转型:
- 向上转型(自动):
Parent p = new Child();
(安全,多态的基础); - 向下转型(强制):
Child c = (Child)p;
(需用instanceof
检查,否则可能抛ClassCastException
)。
- 向上转型(自动):