Anda tidak perlu banyak kode bash untuk mengimplementasikan kelas atau objek di bash.
Katakanlah, 100 baris.
Bash memiliki array asosiatif yang dapat digunakan untuk mengimplementasikan sistem objek sederhana dengan pewarisan, metode, dan properti.
Jadi, Anda mungkin mendefinisikan kelas seperti ini:
class Queue N=10 add=q_add remove=q_remove
Membuat instance dari Antrian ini dapat dilakukan seperti ini:
class Q:Queue N=100
atau
inst Q:Queue N=100
Karena kelas diimplementasikan dengan sebuah array, kelas dan inst benar-benar sinonim - semacam seperti di javascript.
Menambahkan item ke antrian ini dapat dilakukan seperti ini:
$Q add 1 2 aaa bbb "a string"
Menghapus item ke dalam variabel X dapat dilakukan seperti ini:
$Q remove X
Dan struktur dumping suatu objek dapat dilakukan seperti ini:
$Q dump
Yang akan mengembalikan sesuatu seperti ini:
Q {
parent=Queue {
parent=ROOT {
this=ROOT
0=dispatch ROOT
}
class=Queue
N=10
add=q_add
remove=q_remove
0=dispatch Queue
}
class=Q
N=4
add=q_add
remove=q_remove
0=dispatch Q
1=
2=ccc ddd
3=
4=
}
Kelas dibuat menggunakan fungsi kelas seperti ini:
class(){
local _name="$1:" # append a : to handle case of class with no parent
printf "$FUNCNAME: %s\n" $_name
local _this _parent _p _key _val _members
_this=${_name%%:*} # get class name
_parent=${_name#*:} # get parent class name
_parent=${_parent/:/} # remove handy :
declare -g -A $_this # make class storage
[[ -n $_parent ]] && { # copy parent class members into this class
eval _members=\"\${!$_parent[*]}\" # get indices of members
for _key in $_members; do # inherit members from parent
eval _val=\"\${$_parent[$_key]}\" # get parent value
eval $_this[$_key]=\"$_val\" # set this member
done
}
shift 1
# overwrite with specific values for this object
ROOT_set $_this "$@" "0=dispatch $_this" "parent=${_parent:-ROOT}" "class=$_this"
}
CATATAN: Saat mendefinisikan kelas atau instance baru, Anda dapat mengesampingkan nilai atau fungsi anggota apa pun.
Array asosiatif Bash memiliki kekhasan yang membuat pekerjaan ini rapi: $ Q [0]} identik dengan $ Q. Ini berarti bahwa kita dapat menggunakan nama array untuk memanggil fungsi pengiriman metode:
dispatch(){
local _this=$1 _method=$2 _fn
shift 2
_fn="$_this[$_method]" # reference to method name
${!_fn} $_this "$@"
}
Sisi buruknya adalah saya tidak dapat menggunakan [0] untuk data sehingga antrian saya (dalam hal ini) mulai dari indeks = 1. Atau saya bisa menggunakan indeks asosiatif seperti "q + 0".
Untuk mendapatkan dan mengatur anggota Anda dapat melakukan sesuatu seperti ini:
# basic set and get for key-value members
ROOT_set(){ # $QOBJ set key=value
local _this=$1 _exp _key _val
shift
for _exp in "$@"; do
_key=${_exp%%=*}
_val="${_exp#*=}"
eval $_this[$_key]=\"$_val\"
done
}
ROOT_get(){ # $QOBJ get var=key
local _this=$1 _exp _var _key
shift
for _exp in "$@"; do
_var=${_exp%%=*}
_key=${_exp#*=}
eval $_var=\"\${$_this[$_key]}\"
done
}
Dan untuk membuang struktur objek, saya membuat ini:
CATATAN: Ini tidak diperlukan untuk OOP dalam bash, tetapi menyenangkan untuk melihat bagaimana objek dibuat.
# dump any object
obj_dump(){ # obj_dump <object/class name>
local _this=$1 _j _val _key; local -i _tab=${2:-(${#_this}+2)} # add 2 for " {"
_tab+=2 # hanging indent from {
printf "%s {\n" $_this
eval "_key=\"\${!$_this[*]}\""
for _j in $_key; do # print all members
eval "_val=\"\${$_this[\$_j]}\""
case $_j in
# special treatment for parent
parent) printf "%*s%s=" $_tab "" $_j; ${!_val} dump $(( _tab+${#_j}+${#_val}+2 ));;
*) printf "%*s%s=%s\n" $_tab "" $_j "$_val";;
esac
done
(( _tab-=2 ))
printf "%*s}\n" $_tab ""
return 0
}
Desain OOP saya belum mempertimbangkan objek di dalam objek - kecuali kelas bawaan. Anda bisa membuatnya secara terpisah, atau membuat konstruktor khusus seperti kelas (). * obj_dump * perlu dimodifikasi untuk mendeteksi kelas internal untuk mencetaknya secara rekursif.
Oh! dan saya secara manual mendefinisikan kelas ROOT untuk menyederhanakan fungsi kelas :
declare -gA ROOT=( \
[this]=ROOT \
[0]="dispatch ROOT" \
[dump]=obj_dump \
[set]="ROOT_set" \
[get]="ROOT_get" \
)
Dengan beberapa fungsi antrian, saya mendefinisikan beberapa kelas seperti ini:
class Queue \
in=0 out=0 N=10 \
dump=obj_dump \
add=q_add \
empty=q_empty \
full=q_full \
peek=q_peek \
remove=q_remove
class RoughQueue:Queue \
N=100 \
shove=q_shove \
head_drop=q_head_drop
Membuat beberapa contoh Antrian dan membuatnya berfungsi:
class Q:Queue N=1000
$Q add aaa bbb "ccc ddd"
$Q peek X
$Q remove X
printf "X=%s\n" "$X"
$Q remove X
printf "X=%s\n" "$X"
$Q remove X
printf "X=%s\n" "$X"
class R:RoughQueue N=3
$R shove aa bb cc dd ee ff gg hh ii jj
$R dump