Java 面向对象实战:用披萨制作项目理解继承、多态与工厂模式
刚学完 Java 基础语法?想通过实战项目理解面向对象(OOP)核心思想?这篇博客带你用「披萨制作小项目」吃透继承、方法重写、多态、工厂模式!全程保姆级解析,代码 + 思路一步到位,适合前端转 Java / 纯新手入门~
目录
一、项目背景:为什么选 “披萨制作”?
二、需求分析:用户要做什么?
三、核心知识点:用 OOP 解决问题
四、代码分步解析:从父类到工厂
1. 父类Pizza:封装公共属性
2. 子类BaconPizza:继承 + 扩展 + 重写
3. 子类FruitsPizza:和培根披萨逻辑一致
4. 工厂类PizzaStore:解耦对象创建
5. 测试类Test:用户交互入口
五、运行效果:控制台交互示例
场景 1:选培根披萨
场景 2:选水果披萨
六、总结:学到了哪些 OOP 核心?
七、扩展思考:让项目更完善
一、项目背景:为什么选 “披萨制作”?
学编程最头疼的是 **“语法懂了,一写项目就懵”。这个小项目模拟真实场景:用户选披萨类型→输入定制参数→程序输出订单详情。通过 “做披萨” 的流程,把继承、多态、工厂模式 ** 这些抽象概念落地,看完就能实操!
二、需求分析:用户要做什么?
- 选择披萨类型:培根披萨(需填 “培根克数”)、水果披萨(需填 “水果配料”)
- 输入公共参数:披萨大小(寸)、价格(元)
- 输出结果:披萨名称、大小、价格 + 各自的定制信息(培根克数 / 水果配料)
三、核心知识点:用 OOP 解决问题
先记住这张面向对象核心逻辑图(新手建议截图保存):
关键概念拆解:
- 继承(Inheritance):子类(培根 / 水果披萨)复用父类(Pizza)的属性(名称、大小、价格)和方法,减少重复代码。
- 方法重写(Override):子类重写父类的
showPizza
方法,添加自己的 “定制信息”(培根克数 / 水果配料)。 - 多态(Polymorphism):父类类型的变量(
Pizza pizza
)可以指向子类对象(BaconPizza
/FruitsPizza
),调用方法时自动执行子类的重写逻辑。 - 工厂模式(Factory Pattern):用
PizzaStore
工厂类封装对象创建逻辑,用户只需选类型,不用关心 “怎么 new 对象”,降低代码耦合。
四、代码分步解析:从父类到工厂
1. 父类Pizza
:封装公共属性
public class Pizza { // 封装属性:用private隐藏细节,通过getter/setter访问 private String name; // 披萨名称 private int size; // 披萨大小(寸) private int price; // 披萨价格(元) // 核心方法:展示披萨信息(子类会重写它!) public String showPizza() { return \"匹萨的名字是:\" + name + \"\\n匹萨的大小是:\" + size + \"寸\\n匹萨的价格:\" + price + \"元\"; } // 构造器(无参+全参):方便创建对象 public Pizza() {} public Pizza(String name, int size, int price) { this.name = name; this.size = size; this.price = price; } // getter/setter:访问private属性 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; }}
关键理解:父类像 “模板”,定义所有披萨的公共属性和基础行为(如showPizza
),子类继承后可以 “复用 + 扩展”。
2. 子类BaconPizza
:继承 + 扩展 + 重写
public class BaconPizza extends Pizza { // 子类特有属性:培根克数 private int weight; // 构造器:调用父类构造器(super)初始化公共属性 public BaconPizza(String name, int size, int price, int weight) { super(name, size, price); // 必须先调用父类构造器 this.weight = weight; } // 重写父类方法:添加“培根克数”信息 @Override public String showPizza() { // super.showPizza() 调用父类的基础信息 return super.showPizza() + \"\\n培根的克数是:\" + weight + \"克\"; } // getter/setter public int getWeight() { return weight; } public void setWeight(int weight) { this.weight = weight; }}
关键理解:
extends Pizza
:子类继承父类,拿到name
/size
/price
和showPizza
方法。super(...)
:必须在子类构造器第一行调用父类构造器,初始化继承的属性。@Override
:重写父类方法,让 “展示信息” 更具体(加上培根克数)。
3. 子类FruitsPizza
:和培根披萨逻辑一致
public class FruitsPizza extends Pizza { // 子类特有属性:水果配料 private String burdening; public FruitsPizza(String name, int size, int price, String burdening) { super(name, size, price); this.burdening = burdening; } // 重写父类方法:添加“水果配料”信息 @Override public String showPizza() { return super.showPizza() + \"\\n你要加入的水果:\" + burdening; } // getter/setter public String getBurdening() { return burdening; } public void setBurdening(String burdening) { this.burdening = burdening; }}
对比学习:和BaconPizza
的区别仅在于特有属性(克数→配料)和重写内容(培根信息→水果信息),这就是继承的威力—— 复用框架,只改细节!
4. 工厂类PizzaStore
:解耦对象创建
import java.util.Scanner;public class PizzaStore { public static Pizza getPizza(int choice) { Scanner sc = new Scanner(System.in); Pizza p = null; // 父类类型变量,准备指向子类对象(多态!) switch (choice) { case 1: // 培根披萨 System.out.println(\"请录入培根的克数:\"); int weight = sc.nextInt(); System.out.println(\"请录入匹萨的大小:\"); int size = sc.nextInt(); System.out.println(\"请录入匹萨的价格:\"); int price = sc.nextInt(); // 创建子类对象,赋值给父类变量(多态) p = new BaconPizza(\"培根匹萨\", size, price, weight); break; case 2: // 水果披萨 System.out.println(\"请录入你想要加入的水果:\"); String burdening = sc.next(); System.out.println(\"请录入匹萨的大小:\"); int sizeFruit = sc.nextInt(); System.out.println(\"请录入匹萨的价格:\"); int priceFruit = sc.nextInt(); // 创建子类对象,赋值给父类变量(多态) p = new FruitsPizza(\"水果匹萨\", sizeFruit, priceFruit, burdening); break; } return p; // 返回父类类型,调用者无需关心具体子类 }}
关键理解:
- 工厂的作用:把 “创建披萨对象” 的逻辑集中在这里,测试类只需调用
getPizza(choice)
,不用写复杂的new
逻辑,符合单一职责原则。 - 多态体现:
Pizza p
可以是BaconPizza
或FruitsPizza
,返回给调用者时,调用p.showPizza()
会自动执行子类的重写方法!
5. 测试类Test
:用户交互入口
import java.util.Scanner;// 注意:需补充包路径public class Test { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println(\"请选择你想要购买的匹萨(1.培根匹萨 2.水果匹萨):\"); int choice = sc.nextInt(); // 调用工厂创建披萨(父类类型接收子类对象) Pizza pizza = PizzaStore.getPizza(choice); // 多态:实际执行子类的showPizza方法! System.out.println(pizza.showPizza()); }}
执行流程:
用户选类型→工厂创建对应披萨对象→测试类调用showPizza
→输出子类重写后的详细信息。
五、运行效果:控制台交互示例
场景 1:选培根披萨
请选择你想要购买的匹萨(1.培根匹萨 2.水果匹萨):1 请录入培根的克数:23 请录入匹萨的大小:12 请录入匹萨的价格:103 匹萨的名字是:培根匹萨 匹萨的大小是:12寸 匹萨的价格:103元 培根的克数是:23克
场景 2:选水果披萨
请选择你想要购买的匹萨(1.培根匹萨 2.水果匹萨):2 请录入你想要加入的水果:榴莲,芒果,草莓 请录入匹萨的大小:10 请录入匹萨的价格:76 匹萨的名字是:水果匹萨 匹萨的大小是:10寸 匹萨的价格:76元 你要加入的水果:榴莲,芒果,草莓
六、总结:学到了哪些 OOP 核心?
- 继承:子类复用父类属性和方法,减少重复代码(父类写一次,子类直接用)。
- 方法重写:子类根据需求 “定制” 父类方法,让行为更具体(比如培根披萨加克数、水果披萨加配料)。
- 多态:父类类型变量可以指向子类对象,调用方法时自动执行子类逻辑(
Pizza pizza
能调用BaconPizza
的showPizza
)。 - 工厂模式:把对象创建逻辑封装到工厂类,降低代码耦合(测试类不用关心 “怎么 new 披萨”,只管选类型)。
七、扩展思考:让项目更完善
- 添加更多披萨类型:比如海鲜披萨(需填 “海鲜种类”),继承
Pizza
类,重写showPizza
即可。 - 优化输入验证:比如披萨大小不能为负数、价格不能小于成本,在工厂类里加
if
判断。 - 界面化改造:用 Java Swing 或 JavaFX 做图形界面,把控制台交互改成按钮选择(进阶方向)。
写在最后:面向对象的核心是 **“抽象共性,封装变化”**—— 父类抽象公共逻辑,子类封装各自的 “变化点”(培根 / 水果的不同)。这个小项目把复杂概念拆成了 “继承→重写→多态→工厂” 的链条,跟着敲一遍,OOP 思想就吃透一半啦!
如果对你有帮助,点赞 + 收藏鼓励一下呀~ 后续会更 Java Swing 做图形界面的扩展版,关注不迷路!
(代码可直接复制运行,注意包路径和 Scanner 导入~ 有问题评论区见!)