c++設計模式之抽象工廠
阿新 • • 發佈:2022-05-19
棧是一種遵從後進先出LIFO(Last In First Out)
原則的有序集合。新新增或待刪除的元素都儲存在棧的同一端,稱作棧頂,另一端就叫棧底。在棧裡,新元素都靠近棧頂,舊元素都接近棧底。
生活中的案例
- 堆成山的書
- 堆成山的碗具
這些案例中所有的特點都是新增的時候放在最頂端,移除的時候都是從頂端開始移除。
建立一個 Stack
接下來 我們用 JavaScript
這門語言來描述 棧
這種資料解構。
class Stack {
constructor() {
this.items = {};
}
}
我們使用了 JavaScript 的 物件 來 儲存棧結構,接下來我們需要遵循(LIFO)原則,對元素的新增和刪除做一些限制。
Stack 擁有的方法?
-
push(element)
:新增一個 或 幾個新元素 到棧頂。 -
pop()
:移除棧頂的元素,並返回移除的元素。 -
peek()
: 返回棧頂的元素,不做任何改變。 -
isEmpty()
:如果棧裡沒有任何元素就返回true
,反之返回false
。 -
clear()
:移除棧裡所有的元素。 -
size()
: 返回棧裡的元素個數,和 陣列的length
屬性相似。 -
toString()
: 返回當前棧所有元素的內容。
class Stack { constructor() { this.items = {}; // 儲存元素 this.count = 0; // 記錄棧元素的個數 } // methods push(element) { this.items[this.count] = element; this.count++; } pop() { if (this.isEmpty()) { return undefined; } this.count--; const current = this.items[this.count]; delete this.items[this.count]; return current; } peek() { if (this.isEmpty()) { return undefined; } return this.items[this.count - 1]; } clear() { this.items = {}; this.count = 0; // or // while (!this.isEmpty()) { // this.pop() // } } isEmpty() { return this.count === 0; } toString() { if (this.isEmpty()) { return ""; } let str = `${this.items[0]}`; let index = 1; while (index < this.count) { str = `${str},${this.items[index]}`; index++; } return str; } }
操作
const stack = new Stack();
stack.push(1); // 1
stack.push("a"); // 1,a
stack.peek(); // a
stack.pop(); // a
stack.toString(); // 1
問題
在 JavaScript 裡,這個stack
例項可以直接訪問到items
,count
。
const stack = new Stack();
stack.items = { 1: "a", 5: "c" };
我們希望保護內部的元素,只有我們暴露出的方法才能修改內部結構。不幸的是,我們在 Stack 類中宣告的 items 和 count 屬
性並沒有得到保護,因為 JavaScript 的類就是這樣工作的。
下劃線命名約定
一部分開發者喜歡在 JavaScript 中使用下劃線命名約定來標記一個屬性為私有屬性。
class Stack {
constructor() {
this._items = {};
this._count = 0;
}
}
用 ES2015 的限定作用域 Symbol 實現類
const _items = Symbol("stackItems");
class Stack {
constructor() {
this[_items] = {};
}
}
- 不過依然可以訪問到這個屬性
const _items = Symbol("stackItems");
class Stack {
constructor() {
this[_items] = {};
}
}
const stack = new Stack();
const symbolKeys = Object.getOwnPropertySymbols(stack); // [Symbol(stackItems)]
stack[symbolKeys[0]] = { 1: "a", 4: "5" };
stack.toString(); // a,5
使用棧來解決的問題
- JavaScript 執行棧
- 十進位制轉換
function baseConverter(decNumber, base) {
const remStack = new Stack();
const digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
let number = decNumber;
let rem;
let baseString = "";
if (!(base >= 2 && base <= 36)) {
return "";
}
while (number > 0) {
rem = Math.floor(number % base);
remStack.push(rem);
number = Math.floor(number / base);
}
while (!remStack.isEmpty()) {
baseString += digits[remStack.pop()];
}
return baseString;
}
baseConverter(100, 8); // '144'
baseConverter(50, 2); // '110010'