instanceof
の使用はコードのにおいかもしれませんが、私は次のコードの前で問題ないようです。そのような場合にはinstanceof
を使用しないでください。使用するパターンは何ですか?
_<?php
interface Account {}
class PrivateAccount implements Account {}
class PublicAccount implements Account {}
class User {
private $publicAccounts;
private $privateAccounts;
public function hasAccount(Account $account) {
$haystack = [];
if($account instanceof PrivateAccount) {
$haystack = $this->privateAccounts;
} else if($account instanceof PublicAccount) {
$haystack = $this->publicAccounts;
}
foreach($haystack as $someAccount) {
if($account->getId() == $someAccount->getId()) {
return true;
}
}
return false;
}
}
_
具体的には、_$privateAccounts
_および_$publicAccounts
_は、ORMによってリレーショナルデータベースからレイジーロードされるオブジェクトであるため、getId()
の呼び出しはコストがかかります(呼び出しごとにデータベースリクエストが発生します) )。 PublicAccountとPrivateAccountはデータベースの2つのテーブルです。
$haystack = array_merge($privateAccounts, $publicAccounts)
を使用すると、instanceof
の使用が削除されますが、パフォーマンスが低下します。
ええ、オブジェクトのタイプをチェックするコードのにおい。ポリモーフィズムの要点は、型を知っている必要はないということです。
あなたの場合、アカウントの他の派生クラスを渡すとコードが壊れます。
パフォーマンスの面では、遅延ロードされたリストの検索はどちらの方法でも遅くなります。たとえば、すべてのユーザーがすべてプライベートアカウントしか持っていない場合があるため、一般的なケースではこれをプライベートアカウントとパブリックアカウントに分割しても実際には効果がありません。
データベースにFindAccountByUserIdAndAccountIdロジックを実行させるか、ユーザーオブジェクトのaccountIdのリストをキャッシュして、このパフォーマンスの問題を削除します。
私はここでの回答に反対し、この場合instanceof
は大丈夫であると主張します。
PHP
のことを1秒間忘れてみましょう。これがTypeScript
に必要なものです。
type PublicAccount = {
type: "public";
publicAccounts: List<any>; // IDK the type
}
type PrivateAccount = {
type: "private";
privateAccounts: List<any>; // IDK the type
}
type Account = PublicAccount | PrivateAccount;
const hasAccount = (account: Account) => {
switch(account.type) {
case "public":
// type-safe
return account.publicAccounts.size > 0; /** Some logic **/
case "private":
// type-safe
return account.privateAccounts.size > 0; /** Some logic **/
default:
return false;
}
}
これはPHP
に実装された単なる 代数データ型の合計 であると主張します。これは、TypeScript
としてこの高度な型付きキー/値構造を持たないためです。
TypeScript
では問題ないので、なぜPHP
の同じコード(意味論的)が問題になるのでしょうか。
あなたが何をしているかを知っている限り、あなたは大丈夫でなければなりません。
instanceof
を使用する代わりに、アカウントにメソッドisPrivate()
を実装できます。これは、PrivateAccountでは_return true;
_、PublicAccountでは_return false;
_として実装されます。
もう1つのオプションは、二重ディスパッチを使用することです。
ユーザーはメソッドhasPrivateAccount()
とhasPublicAccount()
を実装し、アカウントサブクラスはこれらのメソッドの1つを使用してisAccountOf()
を実装し、ユーザーのhasAccount()
はisAccountOf($this)
。
アカウントが2つの異なるテーブルにあるのはなぜですか?それらのすべてではないにしても、共通の列は多くありませんか?共通の列を共通のテーブルに配置してから、その違いを補助テーブルに結合することはできませんか?参照整合性が必要な場合、補助テーブルの1つを使用したり、2列の制約(2番目はaccountTypeID)を使用したりできませんか?またはマテリアライズされたインデックス付きビューを使用しますか?
なぜこのコードは別のことをする必要があるのか疑問に思います。 privateAccount.accountsとpublicAccount.accountsで十分ではありませんか?どのようにしてpublicAccount.privateAccountsを作成できますか?