Rumah >pembangunan bahagian belakang >tutorial php >Polimorfisme Subtipe - Pelaksanaan Tukar pada Runtime

Polimorfisme Subtipe - Pelaksanaan Tukar pada Runtime

尊渡假赌尊渡假赌尊渡假赌
尊渡假赌尊渡假赌尊渡假赌asal
2025-02-25 18:15:16608semak imbas

Subtype Polymorphism - Swapping Implementation at Runtime

mata teras

  • polimorfisme subtipe dalam reka bentuk berorientasikan objek merujuk kepada keupayaan sistem untuk menentukan satu set kontrak atau antara muka, dan kemudian melaksanakannya dengan subtipe yang berbeza. Ini adalah penting untuk mereka bentuk sistem berskala yang boleh menggunakan kontrak tertentu tanpa memeriksa sama ada pelaksana berada dalam jenis yang diharapkan.
  • Artikel ini menunjukkan penggunaan polimorfisme subtype dengan membangunkan komponen cache yang boleh dimasukkan yang boleh diperluaskan untuk memenuhi keperluan pengguna dengan membangunkan pemandu cache tambahan.
  • Ciri utama komponen cache adalah keupayaannya untuk menukar pemacu cache yang berbeza pada masa runtime tanpa mengubah sebarang kod klien. Ini dicapai dengan menentukan kontrak cache yang kemudian diikuti oleh pelaksanaan yang berbeza, dengan itu mengambil kesempatan daripada polimorfisme.
  • Komponen cache boleh menukar backends pada masa runtime, menonjolkan kepentingan polimorfisme dalam merancang modul yang sangat dihancurkan. Ini membolehkan penyambungan semula mudah pada masa runtime tanpa menyebabkan kelemahan atau isu berkaitan tegar di bahagian lain sistem.
  • Polimorfisme subtipe bukan sahaja menjadikan sistem lebih ortogonal dan lebih mudah untuk skala, tetapi juga kurang cenderung untuk melanggar paradigma teras seperti prinsip terbuka/tertutup dan prinsip "pengaturcaraan berorientasikan antara muka". Ia adalah aspek asas pengaturcaraan berorientasikan objek yang membolehkan fleksibiliti dan kebolehgunaan semula kod.

Ramai orang boleh meragui korelasi antara warisan dan polimorfisme dalam reka bentuk berorientasikan objek? Mungkin sedikit, kebanyakan mereka mungkin disebabkan oleh kejahilan atau pemikiran sempit. Tetapi ada masalah kecil di sini yang tidak boleh diabaikan. Walaupun mudah untuk memahami logik warisan, perkara menjadi lebih sukar apabila membincangkan butiran polimorfisme. Istilah "polimorfisme" adalah menakutkan dengan sendirinya, dengan definisi akademiknya penuh dengan perspektif yang berbeza, yang menjadikannya lebih sukar untuk memahami apa yang sebenarnya di belakangnya. Konsep periferal seperti polimorfisme parameter dan polimorfisme ad hoc (biasanya dilaksanakan dengan kaedah override/overload) mempunyai aplikasi yang penting dalam beberapa bahasa pengaturcaraan, tetapi dalam reka bentuk, mereka boleh mengambil kontrak tertentu (bacaan) apabila abstrak) harus ditinggalkan tanpa memeriksa sama ada pelaksana adalah jenis yang diharapkan. Singkatnya, kebanyakan masa, apa-apa rujukan umum terhadap polimorfisme dalam pengaturcaraan berorientasikan objek secara tersirat dianggap sebagai keupayaan sistem-eksplisit yang digunakan untuk menentukan satu set kontrak atau antara muka yang atau antara muka diikuti oleh pelaksanaan yang berbeza. Polimorfisme "kanonik" ini sering dirujuk sebagai polimorfisme subtipe, kerana pelaksana antara muka dianggap sebagai subtipe mereka, tanpa mengira sama ada terdapat hierarki sebenar. Seperti yang dijangkakan, memahami sifat polimorfisme hanya separuh daripada proses pembelajaran; "Kod" (dalam banyak kes, ia adalah eufemisme yang murah untuk kod mainan). Dalam artikel ini, saya akan menunjukkan kepada anda bagaimana untuk memanfaatkan manfaat yang disediakan oleh polimorfisme dengan membangunkan komponen cache yang boleh dimasukkan. Fungsi teras kemudiannya boleh diperluaskan untuk memenuhi keperluan anda dengan membangunkan pemandu cache tambahan.

Tentukan antara muka dan pelaksanaan komponen

Menu pilihan untuk dipilih adalah tidak hadir ketika membina komponen cache yang boleh diperluaskan (jika anda ragu -ragu tentang ini, lihat saja apa yang ada di sebalik kerangka popular). Walau bagaimanapun, di sini, komponen yang saya berikan mempunyai keupayaan pintar untuk menukar pemandu cache yang berbeza pada masa runtime tanpa mengubah suai kod pelanggan. Jadi, bagaimana anda boleh melakukan ini tanpa banyak usaha semasa proses pembangunan? Nah, langkah pertama adalah ... Ya, tentukan kontrak cache terpencil yang akan diikuti oleh pelaksanaan yang berbeza kemudian, dengan itu memanfaatkan manfaat polimorfisme. Pada tahap yang paling asas, kontrak di atas adalah seperti berikut:

<code class="language-php"><?php namespace LibraryCache;

interface CacheInterface
{
    public function set($id, $data);
    public function get($id);
    public function delete($id);
    public function exists($id);
}</code>
Antara muka

CacheInterface adalah kontrak rangka yang abstrak tingkah laku elemen cache biasa. Dengan antara muka, anda boleh dengan mudah membuat beberapa pelaksanaan cache tertentu yang mematuhi kontrak mereka. Oleh kerana saya ingin memastikan ia mudah dan mudah difahami, pemacu cache yang saya sediakan akan menjadi duo tanpa lemak: yang pertama menggunakan sistem fail sebagai backend asas untuk cache/mendapatkan data, sementara yang kedua menggunakan lanjutan APC Di belakang tabir. Berikut adalah pelaksanaan cache berasaskan fail:

<code class="language-php"><?php namespace LibraryCache;

class FileCache implements CacheInterface
{
    const DEFAULT_CACHE_DIRECTORY = 'Cache/';
    private $cacheDir;

    public function __construct($cacheDir = self::DEFAULT_CACHE_DIRECTORY) {
        $this->setCacheDir($cacheDir);
    }

    public function setCacheDir($cacheDir) {
        if (!is_dir($cacheDir)) {
            if (!mkdir($cacheDir, 0644)) {
                throw InvalidArgumentException('The cache directory is invalid.');
            }
        }
        $this->cacheDir = $cacheDir;
        return $this;
    }

    public function set($id, $data) {
        if (!file_put_contents($this->cacheDir . $id, serialize($data), LOCK_EX)) {
            throw new RuntimeException("Unable to cache the data with ID '$id'.");
        }
        return $this;
    }

    public function get($id) {
        if (!$data = unserialize(@file_get_contents($this->cacheDir . $id, false))) {
            throw new RuntimeException("Unable to get the data with ID '$id'.");
        }
        return $data;
    }

    public function delete($id) {
        if (!@unlink($this->cacheDir . $id)) {
            throw new RuntimeException("Unable to delete the data with ID '$id'.");
        }
        return $this;
    }

    public function exists($id) {
        return file_exists($this->cacheDir . $id);
    }
}</code>
Logik memandu kelas harus mudah difahami. Perkara yang paling relevan di sini setakat ini ialah ia mendedahkan tingkah laku polimorfik yang kemas, kerana ia dengan setia mencapai awal

. Walaupun keupayaan ini manis dan menawan, untuk bahagiannya, saya tidak akan menghargai ia memandangkan matlamat di sini adalah untuk membuat komponen cache yang boleh menukar backends pada masa runtime. Marilah kita berusaha untuk tujuan pengajaran dan membawa satu lagi pelaksanaan yang diselaraskan FileCache ke kehidupan. Pelaksanaan berikut mematuhi kontrak antara muka, tetapi kali ini dengan menggunakan APC untuk memperluaskan kaedah bundling: CacheInterface CacheInterface Kelas

<code class="language-php"><?php namespace LibraryCache;

class ApcCache implements CacheInterface
{
    public function set($id, $data, $lifeTime = 0) {
        if (!apc_store($id, $data, (int) $lifeTime)) {
            throw new RuntimeException("Unable to cache the data with ID '$id'.");
        }
    }

    public function get($id) {
        if (!$data = apc_fetch($id)) {
            throw new RuntimeException("Unable to get the data with ID '$id'.");
        } 
        return $data;
    }

    public function delete($id) {
        if (!apc_delete($id)) {
            throw new RuntimeException("Unable to delete the data with ID '$id'.");
        }
    }

    public function exists($id) {
        return apc_exists($id);
    }
}</code>
bukan pembungkus APC yang paling mempesonakan yang pernah anda lihat dalam kerjaya anda, ia membungkus semua ciri yang anda perlukan untuk menyimpan, mengambil dan memadam data dari ingatan. Mari kita memuji diri kita sendiri, kerana kita telah berjaya melaksanakan modul cache ringan yang backend spesifiknya tidak hanya mudah ditukar pada runtime kerana polimorfisme, tetapi juga sangat mudah untuk menambah lebih banyak backends pada masa akan datang. Hanya tulis pelaksanaan lain yang mematuhi

. Walau bagaimanapun, saya harus menekankan bahawa polimorfisme subtipe sebenar dicapai dengan melaksanakan kontrak yang ditakrifkan melalui pembinaan antara muka, yang merupakan pendekatan yang sangat biasa. Walau bagaimanapun, tiada apa yang boleh menghalang anda daripada menjadi kurang ortodoks dan mendapatkan hasil yang sama dengan menukar antara muka yang diisytiharkan sebagai satu set kaedah abstrak (terletak di kelas abstrak). Sekiranya anda merasa berisiko dan ingin pergi ke laluan itu, anda boleh membina semula kontrak dan pelaksanaan yang sepadan seperti berikut: ApcCache

<code class="language-php"><?php namespace LibraryCache;

interface CacheInterface
{
    public function set($id, $data);
    public function get($id);
    public function delete($id);
    public function exists($id);
}</code>
<code class="language-php"><?php namespace LibraryCache;

class FileCache implements CacheInterface
{
    const DEFAULT_CACHE_DIRECTORY = 'Cache/';
    private $cacheDir;

    public function __construct($cacheDir = self::DEFAULT_CACHE_DIRECTORY) {
        $this->setCacheDir($cacheDir);
    }

    public function setCacheDir($cacheDir) {
        if (!is_dir($cacheDir)) {
            if (!mkdir($cacheDir, 0644)) {
                throw InvalidArgumentException('The cache directory is invalid.');
            }
        }
        $this->cacheDir = $cacheDir;
        return $this;
    }

    public function set($id, $data) {
        if (!file_put_contents($this->cacheDir . $id, serialize($data), LOCK_EX)) {
            throw new RuntimeException("Unable to cache the data with ID '$id'.");
        }
        return $this;
    }

    public function get($id) {
        if (!$data = unserialize(@file_get_contents($this->cacheDir . $id, false))) {
            throw new RuntimeException("Unable to get the data with ID '$id'.");
        }
        return $data;
    }

    public function delete($id) {
        if (!@unlink($this->cacheDir . $id)) {
            throw new RuntimeException("Unable to delete the data with ID '$id'.");
        }
        return $this;
    }

    public function exists($id) {
        return file_exists($this->cacheDir . $id);
    }
}</code>
<code class="language-php"><?php namespace LibraryCache;

class ApcCache implements CacheInterface
{
    public function set($id, $data, $lifeTime = 0) {
        if (!apc_store($id, $data, (int) $lifeTime)) {
            throw new RuntimeException("Unable to cache the data with ID '$id'.");
        }
    }

    public function get($id) {
        if (!$data = apc_fetch($id)) {
            throw new RuntimeException("Unable to get the data with ID '$id'.");
        } 
        return $data;
    }

    public function delete($id) {
        if (!apc_delete($id)) {
            throw new RuntimeException("Unable to delete the data with ID '$id'.");
        }
    }

    public function exists($id) {
        return apc_exists($id);
    }
}</code>

Dari atas ke bawah, ini memang pendekatan polimorfik, yang bertentangan dengan kaedah yang telah dibincangkan sebelumnya. Secara peribadi, ini hanya pernyataan peribadi saya, saya lebih suka menggunakan antara muka membina untuk menentukan kontrak dan menggunakan kelas abstrak hanya apabila merangkumi pelaksanaan boilerplate yang dikongsi oleh beberapa subtipe. Anda boleh memilih kaedah yang paling sesuai dengan keperluan anda. Pada ketika ini, saya dapat meletakkan tirai, menulis beberapa komen mewah yang mewah, membanggakan tentang kemahiran pengekodan kami yang mengagumkan, dan membual tentang fleksibiliti komponen cache kami, tetapi itu akan menjadi slouch kepada kami. Apabila terdapat kod klien yang boleh menggunakan pelbagai pelaksanaan, polimorfisme mempamerkan aspek yang paling menggoda tanpa memeriksa sama ada pelaksanaan ini adalah contoh beberapa jenis, selagi mereka memenuhi kontrak yang diharapkan. Oleh itu, mari kita mendedahkan aspek dengan menghubungkan komponen cache ke kelas pandangan pelanggan asas, yang akan membolehkan kita melakukan beberapa caching HTML yang kemas dengan mudah.

Letakkan pemacu cache ke dalam penggunaan

output HTML caching melalui modul cache contoh kami sangat mudah dan saya akan menyimpan penjelasan yang panjang pada masa lain. Keseluruhan proses cache dapat dipermudahkan ke dalam kelas pandangan yang mudah, sama seperti yang berikut:

<code class="language-php"><?php namespace LibraryCache;

abstract class AbstractCache
{
    abstract public function set($id, $data);
    abstract public function get($id);
    abstract public function delete($id);
    abstract public function exists($id);
}</code>
<code class="language-php"><?php namespace LibraryCache;

class FileCache extends AbstractCache
{
    // the same implementation goes here
}</code>
Lelaki yang paling mempesonakan adalah pembina kelas, yang menggunakan pelaksana awal

dan CacheInterface kaedah. Memandangkan tanggungjawab kaedah terakhir adalah untuk menyingkirkan templat pandangan selepas ia ditolak ke penampan output, lebih baik untuk memanfaatkan keupayaan dan cache keseluruhan dokumen HTML. Anggapkan bahawa templat lalai pandangan mempunyai struktur berikut: render()

<code class="language-php"><?php namespace LibraryCache;

class ApcCache extends AbstractCache
{
    // the same implementation goes here 
}</code>
Sekarang, mari kita bersenang -senang dan cache dokumen dengan memberikan contoh kelas

ke pandangan: ApcCache

<code class="language-php"><?php namespace LibraryView;

interface ViewInterface
{
    public function setTemplate($template);
    public function __set($field, $value);
    public function __get($field);
    public function render();
}</code>
sangat bagus, bukan? Tetapi tunggu! Saya sangat teruja bahawa saya terlupa untuk menyebut bahawa coretan kod di atas akan meletup pada mana -mana sistem yang tidak mempunyai pelanjutan APC dipasang (Pentadbir Sistem Naughty!). Adakah ini bermakna bahawa modul cache yang dibuat dengan teliti tidak lagi boleh diguna semula? Ini adalah tepat di mana pemandu berasaskan fail dimainkan, yang boleh dimasukkan ke dalam kod klien tanpa menerima sebarang aduan:

<code class="language-php"><?php namespace LibraryView;
use LibraryCacheCacheInterface;

class View implements ViewInterface
{
    const DEFAULT_TEMPLATE = 'default';    
    private $template;
    private $fields = array();
    private $cache;

    public function __construct(CacheInterface $cache, $template = self::DEFAULT_TEMPLATE) {
        $this->cache = $cache;
        $this->setTemplate($template);
    }

    public function setTemplate($template) {
        $template = $template . '.php';
        if (!is_file($template) || !is_readable($template)) {
            throw new InvalidArgumentException(
                "The template '$template' is invalid.");   
        }
        $this->template = $template;
        return $this;
    }

    public function __set($name, $value) {
        $this->fields[$name] = $value;
        return $this;
    }

    public function __get($name) {
        if (!isset($this->fields[$name])) {
            throw new InvalidArgumentException(
                "Unable to get the field '$field'.");
        }
        return $this->fields[$name];
    }

    public function render() {
        try {
            if (!$this->cache->exists($this->template)) {
                extract($this->fields);
                ob_start();
                include $this->template;
                $this->cache->set($this->template, ob_get_clean());
            }
            return $this->cache->get($this->template);
        }
        catch (RuntimeException $e) {
            throw new Exception($e->getMessage());
        } 
    }
}</code>
baris kod tunggal di atas secara eksplisit menyatakan bahawa paparan akan menggunakan sistem fail dan bukan memori yang dikongsi untuk cache outputnya. Backend cache beralih dinamik ini secara ringkas menggambarkan mengapa polimorfisme sangat penting apabila mereka bentuk modul yang sangat dihancurkan. Ia membolehkan kita dengan mudah menyambung semula perkara pada masa runtime tanpa menyebarkan artifak yang berkaitan dengan kerentanan/ketegaran ke bahagian lain sistem kami.

Kesimpulan

Polymorphism memang salah satu perkara yang baik dalam hidup, dan apabila anda memahaminya, ia membuat anda tertanya -tanya bagaimana anda boleh lakukan tanpa kesnya berterusan selama sekian lama. Sistem polimorfik sememangnya lebih ortogonal, lebih mudah untuk skala, dan kurang terdedah kepada melanggar paradigma teras seperti prinsip terbuka/tertutup dan prinsip pengaturcaraan berorientasikan antara muka yang bijak. Walaupun agak primitif, modul cache kami adalah contoh yang menonjol dari kelebihan ini. Sekiranya anda tidak memaklumkan permohonan anda untuk memanfaatkan manfaat polimorfisme, anda akan lebih cepat tergesa -gesa kerana anda terlepas jackpot! gambar dari Fotolia

Soalan Lazim Mengenai Polymorphisms Subtipe (FAQ)

Apakah perbezaan utama antara polimorfisme subtipe dan polimorfisme parameter?

polimorfisme subtipe, juga dikenali sebagai polimorfisme inklusi, adalah satu bentuk polimorfisme di mana nama mewakili contoh -contoh pelbagai kategori yang dikaitkan dengan superclass awam. Polimorfisme parameter, sebaliknya, membolehkan fungsi atau jenis data untuk memproses nilai dengan cara yang sama tanpa bergantung pada jenisnya. Polimorfisme parameter adalah cara untuk membuat bahasa lebih ekspresif sambil mengekalkan keselamatan jenis statik penuh.

Bagaimana polimorfisme subtipe berfungsi di Java?

Di Java, polimorfisme subtipe dicapai dengan menggunakan warisan dan antara muka. Pembolehubah rujukan superclass boleh menunjuk kepada objek subclass. Ini membolehkan Java menentukan kaedah mana yang hendak dipanggil pada masa runtime, yang dipanggil penjadualan kaedah dinamik. Ia adalah salah satu ciri kuat Java yang membolehkannya menyokong polimorfisme dinamik.

Bolehkah anda memberikan contoh polimorfisme subtipe?

Sudah tentu, mari kita pertimbangkan contoh mudah di Java. Katakan kita mempunyai superclass yang dipanggil "haiwan" dan dua subclass "anjing" dan "kucing". Kedua -dua kelas "anjing" dan "kucing" menulis semula kaedah "bunyi" kelas "haiwan". Sekarang, jika kita membuat rujukan "haiwan" yang menunjuk kepada objek "anjing" atau "kucing" dan panggil kaedah "bunyi", Java akan membuat keputusan pada runtime kaedah "bunyi" kelas yang hendak dipanggil. Ini adalah contoh polimorfisme subtipe.

Apakah kepentingan polimorfisme subtipe dalam pengaturcaraan?

polimorfisme subtipe adalah aspek asas pengaturcaraan berorientasikan objek. Ia membolehkan fleksibiliti dan kebolehgunaan semula kod. Menggunakan polimorfisme subtipe, anda boleh merancang antara muka yang sama untuk satu set kelas dan kemudian menggunakan antara muka ini untuk berinteraksi dengan objek kelas tersebut dengan cara yang bersatu. Ini akan menghasilkan lebih bersih, lebih intuitif dan lebih mudah untuk mengekalkan kod.

Apakah hubungan antara polimorfisme subtipe dan prinsip penggantian Liskov?

Prinsip Penggantian Liskov (LSP) adalah prinsip reka bentuk berorientasikan objek yang menyatakan bahawa jika program menggunakan kelas asas, ia sepatutnya dapat menggunakan mana-mana subkelasnya tanpa program yang mengetahui. Dalam erti kata lain, objek superclass harus dapat digantikan oleh objek subclass tanpa menjejaskan ketepatan program. Polimorfisme subtipe adalah aplikasi langsung LSP.

Adakah semua bahasa pengaturcaraan menyokong polimorfisme subtipe?

Tidak, tidak semua bahasa pengaturcaraan menyokong polimorfisme subtipe. Ini terutamanya ciri bahasa pengaturcaraan berorientasikan objek yang ditaip secara statik seperti Java, C, dan C#. Bahasa yang ditaip secara dinamik seperti Python dan JavaScript mempunyai bentuk polimorfisme yang berbeza, yang dipanggil jenis itik.

Apakah perbezaan antara polimorfisme statik dan polimorfisme dinamik?

Polimorfisme statik, juga dikenali sebagai polimorfisme kompilasi masa, dicapai melalui kaedah yang berlebihan. Keputusan mengenai kaedah yang hendak dipanggil dibuat pada masa penyusunan. Sebaliknya, polimorfisme dinamik, yang juga dikenali sebagai polimorfisme runtime, dilaksanakan melalui penulisan semula kaedah. Keputusan mengenai kaedah yang hendak dipanggil dibuat pada masa runtime. Polimorfisme subtipe adalah polimorfisme yang dinamik.

Bolehkah anda menerangkan konsep penukaran dalam polimorfisme subtipe?

Upconversion adalah proses merawat objek kelas yang diperolehi sebagai objek kelas asas. Ia adalah aspek utama polimorfisme subtipe. Apabila anda menaikkan objek kelas yang diperoleh, anda boleh memanggil sebarang kaedah yang ditakrifkan dalam kelas asas. Walau bagaimanapun, jika kaedah itu ditulis semula dalam kelas yang diperolehi, versi penulisan semula akan dipanggil.

Apakah penukaran dalam konteks polimorfisme subtipe?

penukaran turun adalah bertentangan dengan penukaran UP. Ia adalah proses menukarkan objek superclass ke dalam subkelas. Apabila anda perlu mengakses kaedah yang hanya wujud dalam subkelas, anda boleh menggunakan penukaran bawah. Walau bagaimanapun, downconversion boleh berbahaya kerana ia boleh menyebabkan ClassCastException jika objek yang ditukar sebenarnya tidak mempunyai jenis yang anda bertukar.

Bagaimanakah polimorfisme subtipe menggalakkan kebolehgunaan kod?

polimorfisme subtipe membolehkan kita menulis lebih banyak kod umum dan boleh diguna semula. Dengan menggunakan rujukan superclass untuk berinteraksi dengan objek subclass, kita boleh menulis kod untuk pelbagai objek selagi mereka semua tergolong dalam subclass superclass yang sama. Ini bermakna kita boleh menambah subkelas baru tanpa mengubah kod yang menggunakan superclass, yang menjadikan kod kita lebih fleksibel dan lebih mudah untuk dikekalkan.

Atas ialah kandungan terperinci Polimorfisme Subtipe - Pelaksanaan Tukar pada Runtime. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn