如何用Java设计自动售货机?是大多在高级Java开发人员面试中经常被问到的好问题之一。在典型的编码面试中,你会得到一个问题描述来开发一个售货机,在有限的时间内,通常2到3小时内,你需要在Java中编写设计文档、工作代码和单元测试。这种Java面试的一个关键优势是可以一次测试候选人的许多基本技能。为了完成售货机的设计、编码和单元测试,候选人需要在这三个方面都非常出色。
顺便说一句,这种真实世界的问题也是一个很好的练习,可以提高你的面向对象分析和设计技能,如果你想成为一个好的应用程序开发人员,这一点非常重要。
通过在Java或任何其他面向对象语言中设计售货机,你不仅可以学习基础知识,如封装、多态或继承,而且还可以在解决问题或设计应用程序时学习使用抽象类和接口的巧妙细节。
通常,这种问题也提供了利用Java设计模式的机会,在这个问题中,我们将使用工厂方法模式来创建不同类型的售货机。我在分享20个Java软件设计问题(此处)时谈到过这个问题,之后,我收到许多反馈要为该问题提供解决方案。
这篇两部分文章将为Java中的售货机问题提供解决方案。顺便说一句,这个问题可以以不同的方式解决,在查看这里给出的解决方案之前,你应该尝试做到这一点。这也是一个重温SOLID和OOPS设计原则的机会,请参阅此处,并准备在代码中使用它们。在Java中设计售货机时,你会发现其中许多适用。
顺便说一句,如果你认真对待学习设计模式和原则,我建议你查看Udemy上的Java设计模式课程。该课程涵盖了SOLID设计原则,如开闭原则和Liskov替换,以及所有重要的面向对象设计模式,如装饰者、观察者、责任链等等。
问题陈述
你需要设计一个售货机,该售货机
-
接受1、5、10、25美分的硬币,即便士、五分币、十分币和25美分。
-
允许用户选择产品:可乐(25美分)、百事可乐(35美分)、汽水(45美分)
-
允许用户通过取消请求获得退款。
-
如果有剩余,则返回所选产品和剩余找零
-
允许售货机供应商重置操作。
需求陈述是问题中最重要的部分。你需要多次阅读问题陈述,以对问题获得高层次的理解,以及你正在尝试解决的问题。通常,需求并不十分清晰,你需要通过阅读问题陈述来制定自己的需求列表。
我喜欢基于要点的需求,因为它很容易跟踪。一些需求也是隐含的,但最好在你的列表中将它们明确化,例如,在这个问题中,如果售货机没有足够的零钱来完成交易,它就不应接受请求。
不幸的是,没有多少书籍或课程教会你这些技能,你需要通过一些真实的工作来自己开发这些技能。
尽管有两种资源帮助我提高了面向对象分析和设计技能,那就是Educative上的《深入面向对象设计面试》,这是一门互动课程,允许你在浏览器上练习面向对象问题,我强烈推荐这门课程来提升你的面向对象设计技能。
Java软件设计问题 - 自动售货机解决方案
第二个资源是Brett D. McLaughlin的《面向对象设计与分析入门》第一版。如果你没有太多面向对象编程经验,这是最好的书籍之一。
解决方案和编码
我对Java售货机的实现具有以下类和接口:
-
VendingMachine
定义售货机的公共API,通常所有高级功能都应在此类中 -
VendingMachineImpl
Vending Machine的一个示例实现 -
VendingMachineFactory
创建不同种类Vending Machine的工厂类 -
Item
表示Vending Machine提供的商品的Java枚举 -
Inventory
表示库存的Java类,用于在Vending Machine内创建存款和商品库存 -
Coin
另一个Java枚举,表示Vending Machine支持的硬币 -
Bucket
一个参数化类来保存两个对象。它有点像Pair类。 -
NotFullPaidException
当用户试图收集一个项目而不支付全额时,Vending Machine会抛出此异常。 -
NotSufficientChangeException
Vending Machine抛出此异常以指示其没有足够的找零来完成此请求。 -
SoldOutExcepiton
如果用户请求的商品已售完,Vending Machine会抛出此异常。
以下是Java中售货机的完整代码,请确保测试此代码,如果遇到任何问题,请告知我。
// VendingMachine.java
public interface VendingMachine {
public long selectItemAndGetPrice(Item item);
public void insertCoin(Coin coin);
public List<Coin> refund();
public Bucket<Item, List<Coin>> collectItemAndChange();
public void reset();
}
// VendingMachineImpl.java
public class VendingMachineImpl implements VendingMachine {
private Inventory<Coin> cashInventory = new Inventory<Coin>();
private Inventory<Item> itemInventory = new Inventory<Item>();
private long totalSales;
private Item currentItem;
private long currentBalance;
public VendingMachineImpl(){
initialize();
}
private void initialize(){
// initialize machine
for(Coin c : Coin.values()){
cashInventory.put(c, 5);
}
for(Item i : Item.values()){
itemInventory.put(i, 5);
}
}
// 其他方法
public void printStats(){
System.out.println("Total Sales : " + totalSales);
System.out.println("Current Item Inventory : " + itemInventory);
System.out.println("Current Cash Inventory : " + cashInventory);
}
}
// 其他类定义
这就是本文第一部分中如何用Java设计售货机的内容。在这一部分中,我们通过创建所有类和编写所有代码来解决问题,但单元测试和设计文档仍在等待中,您将在本文的第二部分中看到。
如果你愿意,你可以通过创建单元测试来运行这个问题,或者也许通过使用线程使其成为一个应用程序,然后使用另一个线程来充当用户。
如果你需要更多面向对象设计问题用于练习,我建议你查看Educative上的《深入面向对象设计面试》课程,这是一个交互式学习平台。该课程由谷歌、Facebook、微软和亚马逊的招聘经理设计,包含这些科技巨头常问的一些面向对象设计问题的解决方案。