一道面試題引起的思考

如下是某場的一道面試題(大概):php

一、一個停車場,車輛入場時,攝像頭記錄下車輛信息
二、屏幕上顯示所接收的車輛的信息狀況(車牌號)以及各層車位的車位餘量
三、停車場一共四層車位,其中的三層都爲普通車位,還有一層爲特殊車位(體如今停車計費價格上面的不一樣)css

看到第一個條件的時候,我大概知道了這道題考察的應該是面向對象相關的,三個條件看完後以及基本確認了。html

說到這裏,簡單地說一下面向對象,至於什麼是面向對象我這裏就很少說了,每一個人也都有本身不一樣的理解,包括它的三要素(封裝、繼承、多態)。前端

簡單地說一下爲何咱們要面向對象,爲何要使用面向對象?說一下個人理解
先拋開面向對象,首先計算機的 程序執行 無非就是 順序、判斷、循環 咱們如今全部用到的語言包括c、java、php... 沒有其它的, 如js中的 if...else, switch...case...就是判斷,for,while就是循環,也包括一些遍歷、遞歸也都是基於這三種方式!咱們天天所產出的代碼,全部的這些都是經過順序、判斷和循環這三個方式都能輕鬆搞定,沒有第四種方式,爲何呢?由於咱們經過這三種方式來解決就實現了一個結構化的問題,也就是咱們經過這三個就能知足全部的需求,也就不須要第四個了這樣的化對咱們的程序就已經結構化了,對於編譯器也能很高效的執行、解析這些東西, 外插一嘴,goto語句其實就是遊離在這三個以外,會致使程序、邏輯的混亂,不多有用基本被淘汰了,不能說他由於效率低,它的效率可能會很高,可是由於脫離告終構化,因此至少在業務代碼上咱們極少使用它。
說到這裏,也就是程勳執行咱們都簡化成 這個結構,而面向對象也讓咱們的數據也簡化了即結構化(這句話也不是我說的,而是ruby語言的做者),書裏說了,面向對象是爲了模擬、表示事件得萬物,好比人、鳥類、到具體服務員類,有具體行爲的類。其實js裏面向對象意義根本不拘泥於此,書上的只是爲了讓咱們好入門好學習而已,它的意義是將零散的數據進行結構化。計算機有個毛病,結構化的程序對於它來講是最簡單的!
簡單解釋一下,咱們瀏覽器加載網頁加載的是什麼?是流,流是什麼呢?其實就是字符串,雖然咱們看到以後是html,css,js代碼,可是代碼不就是字符串嘛,那咱們字符串怎麼辦,瀏覽器拿到字符串首先就是dom節點的解析而後生成生成渲染樹(渲染樹與dom樹不一樣的地方在於,dom樹會把全部的dom節點都展現出來,渲染樹只會展現display非none的元素),都是一步步順序執行的。
相比來講,程序也是如此了,若是咱們的程序中充滿了散亂的數據,那咱們還怎麼按照結構化的要求去操做呢?好比說,經過人作一個對象,人有外貌,行爲,狀態(吃、傳、喝、高矮胖瘦)這麼多東西能夠集成在一個對象中來操做,可是若是沒有面向對象,這些特徵,行爲也就散亂了,一旦散亂了之後還怎麼管理,而且這只是一我的,就有這麼多東西,再來十個,一百個,再來只狗類呢?咱們的程序就成了人心渙散了,固然這些只是舉例子,具體業務還要拿來具體分析。因此面向對象不只符合計算機所喜好的結構化,還能讓咱們管理起來,維護起來,都符合結構化。
再引用雙越老師的一句話:編程就應該簡單&抽象。
有一篇小說裏面有一段話我以爲還蠻有意思的,早期的人們之因此沒有設計出來計算機,就是由於他們想的不夠簡單,而不是不夠複雜,其實計算機很簡單,不就是0和1嗎。
全部說咱們編程,設計時候要作到 結構化,簡單+抽象,抽象完以後才能簡單,簡單的前提是咱們應該抽象好,我認爲這就是咱們爲何要面向對象最主要的緣由,咱們之因此面向對象編程就是由於它能夠抽象,能夠擴展。而不是面向具體,可能這些話對於初學前端的來講很差理解,可是隨着你工做時間的提高,相信很快就會理解的。java

**回到面試題,咱們來分析**
 這個面試題,若是咱們沒有面向對象,面向抽象的概念, 那咱們應該很快就能拿起鍵盤了,一個停車場,三個普通車位,一個豪華車位,一個攝像頭,一個大屏幕顯示器,各類各樣的車,可能咱們很快就能作完,‘設計完’,畢竟面向具體是真的很簡單,要求什麼我就作什麼。。。
 不過說回來,若是面試官再讓你減一個車位或者增長兩個豪華車位,加兩個攝像頭?若是按照咱們以前的來寫,簡單。。。改一下不就好了,加一個豪華車位,加兩個攝像頭。。。其實到這裏想必已經涼涼了。
 下面咱們來使用面向對象
 類圖這裏就再也不畫了
 首先面試題中所提到的咱們均可以當作類,好比停車場是一個類吧,它裏面的車位是一個類吧,攝像頭,屏幕。。。咱們均可以看作是類
 
 停車場,有層位,有攝像頭,屏幕,因此咱們先來建立一個停車場,這一類
 
 class Park {
    constructor () {
     
    }
}

停車場有層位,層位裏面有若干車位
class Floor {
    constructor (num, places) {
        this.num = num
        this.places = places
    }
}

車位也歸爲一類,車位有本身的狀態,有車,無車

class Place {
    constructor () {
        this.empty = true
    }
}

車位分爲普通車位,豪華車位,可是不管是普通仍是豪華,他們也都有本身的狀態,有車,無車,因此咱們直接讓這兩個類繼承車位類
普通車位
class NormalPlace extends Place{
    constructor () {
        super()
    }
}

豪華車位

class SpecialPlace extends Place{
    constructor () {
        super()
    }
}

攝像頭

class Camera {
    constructor () {
    }
}

電腦,能夠記錄全部車的數據

class Computer {
    constructor () {
        this.symbols = {}
    }
}

// 屏幕
class Screen {

}

這樣一看咱們全部類都建立完了,差的是來分析他們的行爲,狀態,聯繫,這裏再也不多作分析。只舉一個簡單的例子,而後上完整代碼

停車場, 有層 攝像圖 屏幕,有出入車時所發生的行爲

class Park {
    constructor (floors) {
        this.floors = floors
        this.camera = new Camera()
        this.screen = new Screen()
    }
    in (car) {

    }
    out (car) {

    }
}
我本身寫了一個簡單的demo,固然也沒有考慮得特別細緻
***完整代碼***
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style>
    body,html{
        height: 100%;
    }
    ul,li {
        list-style: none;
    }
    #inform {
        text-align: center;
        color: #9f9f9f;
        font-size: 18px;
    }
    #inform span {
        color: #ff4a3d;
    }
    #earch {
        text-align: center;
        font-size: 20px;
        color: #2963ff;
    }
</style>
</head>
<body>
<ul id="inform">
<li>第一層車位數量100,空餘車位數量 <span data-num=1>100</span></li>
<li>第二層車位數量100,空餘車位數量 <span data-num=2>100</span></li>
<li>第三層車位數量100,空餘車位數量 <span data-num=3>100</span></li>
<li>第四層車位數量 20,空餘車位數量 <span data-num=4> 20</span></li>
</ul>
<p style="text-align: center; color: #5eb4ff">收入 <span id="price">0</span> 元</p>
<ul id="earch">
<li>統計</li>
</ul>
<script>
let priced = document.getElementById('price')
let earch = document.getElementById('earch')
class Camera {
    constructor () {
        this.computer = new Computer()
    }
    record (car, place, floor) {
        this.computer.show(car)
        return {
            num: car.num,
            symbol: car.symbol,
            inTime: new Date(),
            place,
            floor
        }
    }
}
class Computer {
    constructor () {
        this.symbols = {}
    }
    show (car) {
        console.log(`車牌號爲${car.num}的${car.symbol}駛入`)
        if (this.symbols[car.symbol] !== undefined) {
            this.symbols[car.symbol] = this.symbols[car.symbol] + 1
            document.getElementById(car.symbol).innerText = this.symbols[car.symbol]
        } else {
            this.symbols[car.symbol] = 0
            earch.innerHTML = earch.innerHTML + `<li>${car.symbol}&nbsp;<span id="${car.symbol}">${0}</span>&nbsp;輛<li>`
        }
    }
}
class Screen {
    reload (f, t) {
        let dom = Array.prototype.slice.apply(document.querySelectorAll('#inform span'))
        if (t === '1') {
            dom.map(el => {
                if (el.dataset.num === f + 1 + '') {
                    el.innerText = --el.innerText
                }
            })
        } else {
            dom.map(el => {
                if (el.dataset.num === f + 1 + '') {
                    el.innerText = ++el.innerText
                }
            })
        }
    }
}
class Park {
    constructor (floors) {
        this.floors = floors
        this.camera = new Camera()
        this.screen = new Screen()
        this.carList = {}
        this.fullFloor = []
        this.wait = []
    }
    in (car) {
        let canChoice = []
        let floors = this.floors
        floors.map((el, index) => {
            if (el.emptys > 0) {
                canChoice.push(index)
            }
        })
        if (canChoice.length === 0) {
            if (Math.random() > 0.2) {
                console.warn('沒有找到車位,撤了')
                return 'back'
            } else {
                console.warn(`沒有找到車位,繼續等待`)
                this.in(car)
                return 'wait'
            }
        }
        let fi = canChoice[Math.floor(Math.random() * canChoice.length)]
        let canChoicePlaceIndex = []
        let places = floors[fi].places
        places.map((el, index) => {
            if (el.empty) {
                canChoicePlaceIndex.push(index)
            }
        })
        let pi = Math.floor(Math.random() * canChoicePlaceIndex.length)
        this.carList[car.num] = this.camera.record(car, pi, fi)
        places[pi].in(floors[fi])
        this.screen.reload(fi, '1')
        let outs = Math.ceil(Math.random() * 100000 + 5000)
        setTimeout(() => {
            this.out(car)
        }, outs)
    }
    out (car) {
        let place = this.floors[this.carList[car.num].floor].places[this.carList[car.num].place]
        place.out(this.floors[this.carList[car.num].floor])
        let price = (new Date() - this.carList[car.num].inTime)/1000 * place.price
        this.screen.reload(this.carList[car.num].floor)
        console.log(`車牌號爲${car.num}駛出, 收費 ${price} 元`)
        priced.innerText = (Number(priced.innerText) + Number(price)).toFixed(2)
        delete this.carList[car.num]
    }
}
class Floor {
    constructor (num, places) {
        this.num = num
        this.places = places
        this.emptys = places.length
    }
    inP () {
        this.emptys--
    }
    outP () {
        this.emptys++
    }
}
class Place {
    constructor () {
        this.empty = true
    }
    in (floor) {
        this.empty = false
        floor.inP()
    }
    out (floor) {
        this.empty = true
        floor.outP()
    }
}
class NormalPlace extends Place{
    constructor () {
        super()
        this.color = 'blue'
        this.price = 10
    }
}
class SpecialPlace extends Place{
    constructor () {
        super()
        this.color = 'yellow'
        this.price = 60
    }
}
class Car {
    constructor (type, num, symbol) {
        this.permit = type === '1'
        this.num = num
        this.symbol = symbol
    }
}
// 如下部分所有爲配合實現,請勿浪費時間觀看
let Floors = []
for (let i = 0; i < 3; i++) {
    let places = []
    for (let j = 0; j < 100; j++) {
        places.push(new NormalPlace())
    }
    Floors.push(new Floor(i + 1, places))
}
let specialPlace = []
for (let i = 0; i < 20; i++) {
    specialPlace.push(new SpecialPlace())
}
Floors.push(new Floor(4, specialPlace))
let park = new Park(Floors)
var str = []
for(var i = 65; i < 91; i++){
    str.push(String.fromCharCode(i))
}
let test = {
    s: ['京', '冀', '黑', '蒙', '陝', '戶', '津', '贛', '浣', '深', '藏', '疆' ],
    n: str,
    u: ['奔馳', '勞斯萊斯', '路虎', '大衆', '保時泰', '保時捷', '蘭博基尼', 'QQ', '豐田', '本田', '吉利', '寶馬', '邁巴赫', '公交車', '火車', '坦克', '紅旗', '捷豹', '法拉利', '賓利']
}
let enterTime = 100
setInterval( () => {
    let number = test.s[Math.ceil(Math.random() * test.s.length) - 1] +
        test.n[Math.ceil(Math.random() * test.n.length) - 1] +
        Math.floor(Math.random() * 100000)
    let na = test.u[Math.ceil(Math.random() * test.u.length) - 1]
    let car = new Car('1', number, na)
    park.in(car)
    enterTime = Math.floor(Math.random() * 50)
}, enterTime)
</script>
</body>
</html>

代碼能夠直接粘貼到html裏,直接運行打開,你們只要看各個類之間的聯繫就能夠,具體到行爲的邏輯代碼只是怎麼簡單想怎麼寫就怎麼寫的,固然也有沒考慮全面的,好比各個車位的價格應該也是動態的,爲了趕時間,好多東西我都直接定死了。
抽象好了以後,這樣不管是增長減小變動價錢咱們均可以靈活地處理,每一個類最基礎的行爲和方法幾乎是不變得,咱們只須要變容易變得抽象起來,封裝起來。以後, 就變得‘簡單’面試

歡迎一塊兒探討,你們共同進步!編程

做者:易企秀——Yxaw
相關文章
相關標籤/搜索