日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

面试题之如何用Java设计一个自动售货机

發(fā)布時(shí)間:2023/12/15 java 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 面试题之如何用Java设计一个自动售货机 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

如何用Java設(shè)計(jì)一個(gè)自動售貨機(jī)程序是一個(gè)非常好的Java面試題。大多數(shù)情況會在面試比較senior的Java開發(fā)者的時(shí)候出現(xiàn)。在一個(gè)典型的代碼面試中,你需要在一定的時(shí)間內(nèi)根據(jù)對應(yīng)的條件完成相關(guān)的代碼。通常2到3小時(shí)內(nèi)(面試哪有這么多時(shí)間,哈哈),你需要產(chǎn)生設(shè)計(jì)文檔,可以工作的代碼已經(jīng)單元測試。這樣的Java面試的好處就是你能夠一次性檢測面試者的很多能力。為了能夠完成代碼的設(shè)計(jì),編碼以及單元測試,面試者需要在這三個(gè)方面都比較精通。

另外,這種真實(shí)的問題可以提升你面向?qū)ο蠓治龊驮O(shè)計(jì)能力的技能,假如你想成為一個(gè)很好的應(yīng)用開發(fā)者,那么這個(gè)技能就很重要。

要想用Java或者別的面向?qū)ο蟮恼Z言來設(shè)計(jì)一個(gè)自動售貨機(jī),你不僅僅需要了解最基本的東西,比如封裝(Encapsulation),多態(tài)(Polymorphism)或者繼承(Inheritance),你還需要理解如何使用抽象類和接口的細(xì)節(jié),這樣才能解決問題或者設(shè)計(jì)一個(gè)好的應(yīng)用。

通常這種問題,還會給你一個(gè)使用設(shè)計(jì)模式的機(jī)會,因?yàn)樵谶@個(gè)問題中你可以使用工廠模式去創(chuàng)建不同的售貨機(jī)。我在20個(gè)Java軟件開發(fā)的問題一文中曾今討論過這個(gè)問題,那之后,我收到了很多反饋關(guān)于解決這個(gè)問題的方案。

這篇文章,我們將會提供一個(gè)自動售貨機(jī)問題的解決方案。順便說一下,其實(shí)這個(gè)問題有很多種解決的方案,你應(yīng)當(dāng)在看本文之前自己先嘗試一下。你也需要先復(fù)習(xí)一下SOLID和OOPS的設(shè)計(jì)原則,我們會在代碼中使用到他們。當(dāng)你設(shè)計(jì)自動售貨機(jī)的時(shí)候,你會發(fā)現(xiàn)我們會用到其中很多的相關(guān)內(nèi)容。

另外,假如你對設(shè)計(jì)模式和原則感興趣,我推薦你看看Udemy的“Java設(shè)計(jì)模式”這門課。這門課包括SOLID的設(shè)計(jì)模式,比如開閉原則(open closed)以及里氏替代(Liskov Substitution),當(dāng)然也包括所有的面向?qū)ο蟮脑O(shè)計(jì)模式,比如裝飾,觀察,責(zé)任鏈等等。

問題陳述

你需要設(shè)計(jì)一個(gè)這樣的自動售貨機(jī):

  • 能夠接收1分錢,5分錢,10分錢以及25分錢等等。
  • 允許客戶來選擇產(chǎn)品,比如可樂(25), 百事(35),蘇打(45)
  • 允許用戶取消請求來退錢
  • 返回選擇的產(chǎn)品,并且找零(假如需要的話)
  • 允許售貨機(jī)的提供商做reset的操作。
  • 需求部分是這個(gè)問題最重要的部分。你需要仔細(xì)地閱讀這個(gè)部分,然后對這個(gè)問題有一個(gè)高層的理解,然后思考如何來解決它。通常來說,需求部分都是不明確的,你需要通過閱讀問題的陳述來列出一系列的你自己理解的需求。

    我們喜歡指出基本的需求,因?yàn)樗麄兒苋菀讈砀櫋R恍┬枨笫呛茈[式的,我們最好把他們在你的列表中顯式列出來。比如在這個(gè)問題中,假如售貨機(jī)沒有足夠的零錢來找回,那么他就不應(yīng)該接收相應(yīng)的請求。

    很不幸,沒有什么課本或者課程來告訴你這些,你只有在真實(shí)的環(huán)境中做過這些才能知道。當(dāng)然,有兩本書曾幫助我改進(jìn)我的面向?qū)ο蠓治龊驮O(shè)計(jì)的能力,他們是《深入淺出面向?qū)ο蠓治龊驮O(shè)計(jì)》 (Head First Object Oriented Design and Analysis),假如你沒有相關(guān)的面向?qū)ο缶幊痰慕?jīng)驗(yàn),那么這本書非常值得推薦。

    ?

    另外一本書是UML for Java Progrmmers,它是一本開發(fā)應(yīng)用和系統(tǒng)設(shè)計(jì)方面非常好的書,值得推薦。它的做著是Robert C. Martin。我已經(jīng)讀過他的很多本書,比如Clean Code, Clean Coder以及一本關(guān)于使用Agile進(jìn)行軟件開發(fā)的書。他在OOP方面的教學(xué)大概是最好的。

    ?

    這本書有一個(gè)類似的問題:設(shè)計(jì)一個(gè)咖啡機(jī)。因此,假如你想有更多的實(shí)踐,或者希望提升你的面向?qū)ο蟮脑O(shè)計(jì)能力,你可以參考那個(gè)問題。那個(gè)問題也是一個(gè)很好的學(xué)習(xí)的作業(yè)。

    方案和代碼

    我的關(guān)于售貨機(jī)的Java實(shí)現(xiàn)包括以下的類和接口:

    VendingMachine

    它定義了售貨機(jī)的所有公用API,通常所有的高級功能應(yīng)該都在這個(gè)類里面。

    VendingMachineImpl

    售貨機(jī)的示例實(shí)現(xiàn)

    VendingMachineFactory

    這是一個(gè)工廠類,用來創(chuàng)建不同的售貨機(jī)

    Item

    Java的Enum關(guān)于售貨機(jī)服務(wù)的項(xiàng)目

    Inventory

    這個(gè)類用來展示庫存,用來創(chuàng)建售貨機(jī)中的案例和物品清單。

    Coin

    一個(gè)Java Enum用來表示支持的貨幣。

    Bucket

    一個(gè)用于容納兩個(gè)對象的參數(shù)化類。

    NotFullPaidException

    這是一個(gè)exception,主要用來表示一個(gè)用戶選擇了一個(gè)項(xiàng)目,但是沒有付足夠的錢。

    NotSufficientChangeException

    這個(gè)Exception用來表示售貨機(jī)沒有錢的用來找零。

    SoldOutException

    當(dāng)用戶選擇一個(gè)已經(jīng)賣完了的產(chǎn)品時(shí),會拋出這個(gè)exception

    ?

    怎樣在Java中設(shè)計(jì)售貨機(jī)

    下面就是完整的代碼,你可以測試一下這個(gè)代碼,如果有什么問題告訴我。

    VendingMachine.java

    它定義了售貨機(jī)的所有公用API,通常所有的高級功能應(yīng)該都在這個(gè)類里面。

    package vending;import java.util.List;/** * Decleare public API for Vending Machine */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

    一個(gè)VendingMachine接口實(shí)現(xiàn)示例,你可以在你的辦公室,公交車站,火車站以及公共的地方看到他

    package vending; import java.util.ArrayList; import java.util.Collections; import java.util.List; /*** Sample implementation of Vending Machine in Java* @author Javin Paul*/ 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 with 5 coins of each denomination//and 5 cans of each Item for(Coin c : Coin.values()){cashInventory.put(c, 5);}for(Item i : Item.values()){itemInventory.put(i, 5);}}@Overridepublic long selectItemAndGetPrice(Item item) {if(itemInventory.hasItem(item)){currentItem = item;return currentItem.getPrice();}throw new SoldOutException("Sold Out, Please buy another item");} @Overridepublic void insertCoin(Coin coin) {currentBalance = currentBalance + coin.getDenomination();cashInventory.add(coin);} @Overridepublic Bucket<Item, List<Coin>> collectItemAndChange() {Item item = collectItem();totalSales = totalSales + currentItem.getPrice();List<Coin> change = collectChange();return new Bucket<Item, List<Coin>>(item, change);}private Item collectItem() throws NotSufficientChangeException,NotFullPaidException{if(isFullPaid()){if(hasSufficientChange()){itemInventory.deduct(currentItem);return currentItem;} throw new NotSufficientChangeException("Not Sufficient change in Inventory");}long remainingBalance = currentItem.getPrice() - currentBalance;throw new NotFullPaidException("Price not full paid, remaining : ", remainingBalance);}private List<Coin> collectChange() {long changeAmount = currentBalance - currentItem.getPrice();List<Coin> change = getChange(changeAmount);updateCashInventory(change);currentBalance = 0;currentItem = null;return change;}@Overridepublic List<Coin> refund(){List<Coin> refund = getChange(currentBalance);updateCashInventory(refund);currentBalance = 0;currentItem = null;return refund;}private boolean isFullPaid() {if(currentBalance >= currentItem.getPrice()){return true;}return false;} private List<Coin> getChange(long amount) throws NotSufficientChangeException{List<Coin> changes = Collections.EMPTY_LIST;if(amount > 0){changes = new ArrayList<Coin>();long balance = amount;while(balance > 0){if(balance >= Coin.QUARTER.getDenomination() && cashInventory.hasItem(Coin.QUARTER)){changes.add(Coin.QUARTER);balance = balance - Coin.QUARTER.getDenomination();continue;}else if(balance >= Coin.DIME.getDenomination() && cashInventory.hasItem(Coin.DIME)) {changes.add(Coin.DIME);balance = balance - Coin.DIME.getDenomination();continue;}else if(balance >= Coin.NICKLE.getDenomination() && cashInventory.hasItem(Coin.NICKLE)) {changes.add(Coin.NICKLE);balance = balance - Coin.NICKLE.getDenomination();continue;}else if(balance >= Coin.PENNY.getDenomination() && cashInventory.hasItem(Coin.PENNY)) {changes.add(Coin.PENNY);balance = balance - Coin.PENNY.getDenomination();continue;}else{throw new NotSufficientChangeException("NotSufficientChange,Please try another product");}}}return changes;}@Overridepublic void reset(){cashInventory.clear();itemInventory.clear();totalSales = 0;currentItem = null;currentBalance = 0;} public void printStats(){System.out.println("Total Sales : " + totalSales);System.out.println("Current Item Inventory : " + itemInventory);System.out.println("Current Cash Inventory : " + cashInventory);} private boolean hasSufficientChange(){return hasSufficientChangeForAmount(currentBalance - currentItem.getPrice());}private boolean hasSufficientChangeForAmount(long amount){boolean hasChange = true;try{getChange(amount);}catch(NotSufficientChangeException nsce){return hasChange = false;}return hasChange;} private void updateCashInventory(List change) {for(Coin c : change){cashInventory.deduct(c);}}public long getTotalSales(){return totalSales;}}

    VendingMachineFactory.java

    一個(gè)工廠類,用來創(chuàng)建不同的售貨機(jī)

    package vending; /** * Factory class to create instance of Vending Machine, this can be extended to create instance of * different types of vending machines. * @author Javin Paul */public class VendingMachineFactory { public static VendingMachine createVendingMachine() { return new VendingMachineImpl(); }}

    Coin.java

    一個(gè)Java的enum用來表示售貨機(jī)支持的貨幣

    package vending; /*** Coins supported by Vending Machine.* @author Javin Paul*/ public enum Coin {PENNY(1), NICKLE(5), DIME(10), QUARTER(25);private int denomination;private Coin(int denomination){this.denomination = denomination;}public int getDenomination(){return denomination;} }

    Inventory.java

    一個(gè)用來表示庫存的類,用來創(chuàng)建售貨機(jī)中的案例和物品清單。

    package vending; import java.util.HashMap; import java.util.Map; /** * An Adapter over Map to create Inventory to hold cash and * Items inside Vending Machine * @author Javin Paul */ public class Inventory<T> { private Map<T, Integer> inventory = new HashMap<T, Integer>(); public int getQuantity(T item){ Integer value = inventory.get(item); return value == null? 0 : value ;} public void add(T item){ int count = inventory.get(item); inventory.put(item, count+1);} public void deduct(T item) { if (hasItem(item)) {int count = inventory.get(item);inventory.put(item, count - 1);} } public boolean hasItem(T item){return getQuantity(item) > 0;}public void clear(){ inventory.clear(); } public void put(T item, int quantity) { inventory.put(item, quantity); } }

    Bucket.java

    一個(gè)帶參數(shù)的工具類,可以產(chǎn)生兩個(gè)對象

    package vending; /** * A parameterized utility class to hold two different object. * @author Javin Paul */ public class Bucket<E1, E2> { private E1 first;private E2 second;public Bucket(E1 first, E2 second){this.first = first;this.second = second;} public E1 getFirst(){ return first; } public E2 getSecond(){return second;} }

    NotFullPaidException.java

    這是一個(gè)exception,主要用來表示一個(gè)用戶選擇了一個(gè)項(xiàng)目,但是沒有付足夠的錢。

    package vending; public class NotFullPaidException extends RuntimeException {private String message;private long remaining;public NotFullPaidException(String message, long remaining) {this.message = message;this.remaining = remaining;}public long getRemaining(){return remaining;}@Overridepublic String getMessage(){return message + remaining;} }

    NotSufficientChangeException.java

    這個(gè)Exception用來表示售貨機(jī)沒有錢的用來找零。

    package vending; public class NotSufficientChangeException extends RuntimeException {private String message;public NotSufficientChangeException(String string) {this.message = string;}@Overridepublic String getMessage(){return message;}}

    SoldOutException.java

    當(dāng)用戶選擇一個(gè)已經(jīng)賣完了的產(chǎn)品時(shí),會拋出這個(gè)exception

    package vending; public class SoldOutException extends RuntimeException {private String message;public SoldOutException(String string) {this.message = string;}@Overridepublic String getMessage(){return message;}}

    ?關(guān)于設(shè)計(jì)售貨機(jī)的第一部分就到這里結(jié)束了。在這個(gè)部分中,我們通過創(chuàng)建所有的類,以及寫相關(guān)的代碼解決了這個(gè)問題。但是單元測試和設(shè)計(jì)文檔并沒有做,關(guān)于這一部分你可以關(guān)注我們的第二部分。

    假如你愿意的話,你可以為這個(gè)問題創(chuàng)建單元測試,或者在一個(gè)thread中運(yùn)行他,然后再建一個(gè)thread來調(diào)用它,這樣就類似模擬一個(gè)用戶。你也可以閱讀UML For Java Programmers中的相關(guān)內(nèi)容。

    進(jìn)一步閱讀:

    Design Pattern Library

    From 0 to 1: Design Patterns – 24 That Matter – In Java

    Java Design Patterns – The Complete Masterclass

    ?

    更多原創(chuàng),敬請關(guān)注微信公眾號,每日更新業(yè)界最新資訊:

    歡迎訪問個(gè)人小站:?https://donggeitnote.com/2020/07/06/javavendingmachine/

    總結(jié)

    以上是生活随笔為你收集整理的面试题之如何用Java设计一个自动售货机的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。