mata teras
Walaupun ia tidak sepenuhnya mematuhi spesifikasi, boleh dikatakan bahawa orthogonality adalah intipati sistem perisian berdasarkan prinsip "reka bentuk yang baik", di mana modul -modul itu dipisahkan dari satu sama lain, menjadikan sistem kurang terdedah kepada masalah yang tegar dan rapuh. Sudah tentu, lebih mudah untuk bercakap tentang kelebihan sistem ortogonal daripada benar -benar menjalankan sistem pengeluaran; Walau bagaimanapun, ia bukan konsep utopia untuk mencapai komponen yang sangat dihancurkan dalam sistem. Pelbagai konsep pengaturcaraan seperti polimorfisme membolehkan reka bentuk program fleksibel, yang bahagiannya boleh dihidupkan pada masa runtime, dan kebergantungan mereka dapat dinyatakan dalam bentuk abstrak dan bukannya pelaksanaan konkrit. Saya akan mengatakan bahawa moto lama "pengaturcaraan berorientasikan antara muka" telah diterima secara meluas dari masa ke masa, sama ada kita melaksanakan infrastruktur atau logik aplikasi. Walau bagaimanapun, apabila melangkah ke dalam bidang model domain, keadaannya sangat berbeza. Terus terang, ini adalah senario yang boleh diramal. Lagipun, mengapa rangkaian objek yang saling berkaitan (yang mempunyai data dan tingkah laku yang terhad oleh peraturan perniagaan yang jelas) menjadi polimorfik? Ia tidak masuk akal dengan sendirinya. Walau bagaimanapun, terdapat beberapa pengecualian untuk peraturan ini, yang akhirnya boleh digunakan untuk keadaan ini. Pengecualian pertama ialah penggunaan proksi maya, yang secara efektif antara muka yang sama seperti objek domain sebenar. Satu lagi pengecualian ialah apa yang dipanggil "Null Case", yang merupakan kes khas di mana operasi mungkin berakhir dengan memberikan atau mengembalikan nilai null dan bukannya mengisi entiti yang dipenuhi dengan baik. Dalam pendekatan tradisional bukan polimorfik, pengguna model mesti menyemak nilai-nilai nol "berbahaya" ini dan mengendalikan keadaan dengan anggun, mengakibatkan letupan pernyataan bersyarat di seluruh kod. Mujurlah, keadaan yang seolah-olah mengelirukan ini mudah diselesaikan dengan hanya membuat pelaksanaan pelbagai cawangan objek domain yang akan melaksanakan antara muka yang sama seperti objek yang dipersoalkan, kecuali kaedahnya tidak melakukan apa-apa, jadi klien akan menjadi kod yang dibebaskan dari Berulang -ulang memeriksa nilai null hodoh semasa melakukan operasi. Tidak menghairankan, pendekatan ini adalah corak reka bentuk yang dipanggil objek kosong yang membawa kelebihan polimorfisme kepada yang melampau. Dalam artikel ini, saya akan menunjukkan manfaat corak ini dalam beberapa kes dan menunjukkan kepada anda bagaimana ia melekat pada kaedah polimorfik.
merawat keadaan bukan polimorfik
seperti yang diharapkan, terdapat beberapa cara untuk mencuba apabila menunjukkan kelebihan corak objek kosong. Pendekatan yang sangat mudah yang saya dapati adalah untuk melaksanakan pemetaan data yang mungkin kembali kembali nilai nol dari pencari tujuan umum. Katakan kami telah berjaya mencipta model domain rangka yang terdiri daripada hanya satu entiti pengguna. Antara muka dan kelasnya adalah seperti berikut:
<?php namespace Model; interface UserInterface { public function setId($id); public function getId(); public function setName($name); public function getName(); public function setEmail($email); public function getEmail(); }
<?php namespace Model; class User implements UserInterface { private $id; private $name; private $email; public function __construct($name, $email) { $this->setName($name); $this->setEmail($email); } public function setId($id) { if ($this->id !== null) { throw new BadMethodCallException( "The ID for this user has been set already."); } if (!is_int($id) || $id throw new InvalidArgumentException( "The ID for this user is invalid."); } $this->id = $id; return $this; } public function getId() { return $this->id; } public function setName($name) { if (strlen($name) 30) { throw new InvalidArgumentException( "The user name is invalid."); } $this->name = $name; return $this; } public function getName() { return $this->name; } public function setEmail($email) { if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { throw new InvalidArgumentException( "The user email is invalid."); } $this->email = $email; return $this; } public function getEmail() { return $this->email; } }
Kelas Pengguna adalah struktur reaktif yang melaksanakan beberapa mutator/aksesor untuk menentukan beberapa data dan tingkah laku pengguna. Dengan kelas domain yang dibina ini, kita kini boleh melangkah lebih jauh dan menentukan pemetaan data asas yang mengasingkan model domain dan lapisan data kami antara satu sama lain.
<?php namespace ModelMapper; use LibraryDatabaseDatabaseAdapterInterface, ModelUser; class UserMapper implements UserMapperInterface { private $adapter; public function __construct(DatabaseAdapterInterface $adapter) { $this->adapter = $adapter; } public function fetchById($id) { $this->adapter->select("users", array("id" => $id)); if (!$row = $this->adapter->fetch()) { return null; } return $this->createUser($row); } private function createUser(array $row) { $user = new User($row["name"], $row["email"]); $user->setId($row["id"]); return $user; } }
Perkara pertama yang sepatutnya muncul ialah kaedah FetchById () Mapper adalah nakal di blok, kerana ia secara berkesan mengembalikan null apabila tiada pengguna dalam pangkalan data yang sepadan dengan ID yang diberikan. Atas sebab -sebab yang jelas, keadaan canggung ini menjadikan kod klien harus bekerja keras untuk memeriksa nilai null setiap kali ia memanggil pencari mapper.
<?php use LibraryLoaderAutoloader, LibraryDatabasePdoAdapter, ModelMapperUserMapper; require_once __DIR__ . "/Library/Loader/Autoloader.php"; $autoloader = new Autoloader; $autoloader->register(); $adapter = new PdoAdapter("mysql:dbname=test", "myusername", "mypassword"); $userMapper = new UserMapper($adapter); $user = $userMapper->fetchById(1); if ($user !== null) { echo $user->getName() . " " . $user->getEmail(); }
Pada pandangan pertama, tidak akan ada masalah, hanya periksa di satu tempat. Tetapi jika garis yang sama muncul dalam pelbagai pengawal halaman atau lapisan perkhidmatan, adakah anda akan bertemu dengan dinding bata? Sebelum anda menyedarinya, null yang tidak bersalah yang dikembalikan oleh mapper akan menghasilkan banyak keadaan berulang, yang merupakan pertanda yang buruk dari reka bentuk yang buruk.
Keluarkan pernyataan keadaan dari kod klien
Walau bagaimanapun, tidak perlu risau, kerana ini betul -betul berlaku di mana corak objek kosong menunjukkan mengapa polimorfisme adalah rahmat. Jika kita mahu menyingkirkan kenyataan bersyarat yang menjengkelkan sekali dan untuk semua, kita boleh melaksanakan versi polimorfik kelas pengguna sebelumnya.
<?php namespace Model; class NullUser implements UserInterface { public function setId($id) { } public function getId() { } public function setName($name) { } public function getName() { } public function setEmail($email) { } public function getEmail() { } }
Kaedah Mapper's CreateUser () menyembunyikan keadaan kecil kerana kini bertanggungjawab untuk membuat pengguna kosong apabila ID yang diluluskan kepada pencari tidak mengembalikan pengguna yang sah. Walau bagaimanapun, kos nuanced ini bukan sahaja menjimatkan kerja kod klien yang melakukan banyak cek berulang, tetapi juga menjadikannya pengguna longgar yang tidak akan mengadu apabila ia harus berurusan dengan pengguna kosong.
<?php namespace ModelMapper; use LibraryDatabaseDatabaseAdapterInterface, ModelUser, ModelNullUser; class UserMapper implements UserMapperInterface { private $adapter; public function __construct(DatabaseAdapterInterface $adapter) { $this->adapter = $adapter; } public function fetchById($id) { $this->adapter->select("users", array("id" => $id)); return $this->createUser($this->adapter->fetch()); } private function createUser($row) { if (!$row) { return new NullUser; } $user = new User($row["name"], $row["email"]); $user->setId($row["id"]); return $user; } }
<?php namespace Model; interface UserInterface { public function setId($id); public function getId(); public function setName($name); public function getName(); public function setEmail($email); public function getEmail(); }
Kelemahan utama pendekatan polimorfik ini adalah bahawa sebarang aplikasi yang menggunakannya akan menjadi terlalu longgar kerana ia tidak pernah terhempas ketika berurusan dengan entiti yang tidak sah. Dalam kes yang paling teruk, antara muka pengguna hanya akan menunjukkan beberapa baris kosong, tetapi tidak ada yang benar -benar bising membuat kita jijik. Ini amat jelas apabila mengimbas pelaksanaan semasa kelas Nulluser awal. Walaupun ia boleh dilaksanakan, belum lagi yang disyorkan, ia juga boleh merangkum logik dalam objek kosong sambil mengekalkan polimorfisme tidak berubah. Saya juga boleh mengatakan bahawa objek kosong adalah sempurna untuk merangkumi data dan tingkah laku lalai yang harus didedahkan kepada kod klien hanya dalam beberapa kes khas. Sekiranya anda cukup bercita -cita tinggi dan ingin mencuba konsep ini dengan objek pengguna kosong yang mudah, kelas Nulluser semasa boleh ditakrifkan seperti berikut:
<?php namespace Model; class User implements UserInterface { private $id; private $name; private $email; public function __construct($name, $email) { $this->setName($name); $this->setEmail($email); } public function setId($id) { if ($this->id !== null) { throw new BadMethodCallException( "The ID for this user has been set already."); } if (!is_int($id) || $id throw new InvalidArgumentException( "The ID for this user is invalid."); } $this->id = $id; return $this; } public function getId() { return $this->id; } public function setName($name) { if (strlen($name) 30) { throw new InvalidArgumentException( "The user name is invalid."); } $this->name = $name; return $this; } public function getName() { return $this->name; } public function setEmail($email) { if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { throw new InvalidArgumentException( "The user email is invalid."); } $this->email = $email; return $this; } public function getEmail() { return $this->email; } }
Versi Nulluser yang dipertingkatkan sedikit lebih ekspresif daripada pendahulunya yang tenang, kerana getternya menyediakan beberapa pelaksanaan asas untuk mengembalikan beberapa mesej lalai ketika meminta pengguna yang tidak sah. Walaupun remeh, perubahan ini mempunyai kesan positif terhadap bagaimana kod klien mengendalikan pengguna kosong, kerana pengguna kali ini sekurang-kurangnya tahu bahawa beberapa masalah timbul apabila mereka cuba mengekstrak pengguna yang tidak wujud dari penyimpanan. Ini adalah kejayaan yang baik, bukan sahaja menunjukkan cara melaksanakan objek kosong yang sebenarnya tidak kosong sama sekali, tetapi juga betapa mudahnya untuk memindahkan logik di dalam objek yang relevan berdasarkan keperluan khusus.
Kesimpulan
Sesetengah mungkin mengatakan bahawa melaksanakan objek kosong adalah menyusahkan, terutamanya dalam PHP, di mana konsep teras OOP (seperti polimorfisme) adalah kurang dipandang rendah. Mereka betul -betul sedikit. Walau bagaimanapun, penggunaan secara beransur -ansur prinsip pengaturcaraan yang boleh dipercayai dan corak reka bentuk, serta tahap kematangan yang dicapai oleh model objek bahasa, adalah untuk terus maju dan mula menggunakan beberapa "barangan mewah" yang dianggap kompleks dan tidak realistik Tidak lama dahulu menyediakan semua asas yang diperlukan. Corak objek NULL jatuh ke dalam kategori ini, tetapi pelaksanaannya sangat mudah dan elegan sehingga sukar untuk tidak merasa menarik ketika membersihkan pemeriksaan NULL pendua dalam kod klien. gambar dari Fotolia
(disebabkan oleh batasan ruang, bahagian FAQ dalam teks asal ditinggalkan di sini.)
Atas ialah kandungan terperinci PHP Master | Corak Objek Null - Polimorfisme dalam Model Domain. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!