評価評価を設計します

多くの場合、サイトの訪問者がオブジェクト(メモ、コメント、引用、写真、ビデオなど)を評価する可能性を理解する必要があります。 それをプログラムするには?



まず、評価の対象と評価の対象があります。 後者は、たとえば、登録ユーザー、未登録ユーザー(ゲスト)などです。



タスクを実装するモジュールに、評価投票の可能性を付与するサブジェクト領域の特定のエンティティの弱い一貫性を確保するために、オブジェクト( Rating_Object )とサブジェクト( Rating_Subject )に別々のクラスを選択します。 これらのクラスは両方とも固有であり、 アクティブレコードとして実装されます。 インスタンスのRating_Objectに記事やフォトグラムのすべての種類を結びつけることができるように、我々は、インタフェースRating_Ratableを提供します。



interface Rating_Ratable { /** * @return Rating_Object */ public function asRatingObject(); }
      
      







このインターフェイスは、たとえば次のようにArticleクラスなどで実装できるようになりました。



 class Article extends ActiveRecord implements Rating_Ratable { public function setTableDefinition() { $this->hasReferenceColumn("rating_object_id"); } public function setUp() { $this->hasOne("Rating_Object as rating_object", array("local" => "rating_object_id", "foreign" => "id")); } public function asRatingObject() { return $this->rating_object; } }
      
      







評価対象についても同じことを行います。 投票できる特定のエンティティごとにサブジェクトの識別子を保存するだけです。 ほとんどの場合、サイトへの現在の訪問者のアクティブなレコードがあるため(ゲストは一連の情報で識別できます。したがって、データベースに彼のレコードを作成するために、まだこれを行っていない場合は開始します)、適切なクラスフィールドrating_subject_id。



将来、サイトへの訪問者ではないエンティティからの評価の投票を受け入れる必要がある場合(たとえば、サードパーティの評価からデータを取得するため)、そのようなエンティティの各インスタンスにRating_Subjectの個別のインスタンスを簡単に添付することもできます。



ですから、評価できる人と評価できる人がいます。 それらを接続する必要があります。 これを行うには、Rating_Voteクラスを入力してください- OBJECT_IDフィールドを持つアクティブなレコード、subject_id、意見を。 このエンティティは、そのオブジェクトを設定し、特定の推定 - 最後のフィールドには、規模の評価の具体的な選択です。



ここで、可能な推定値のスペクトルが異なる場合があることに注意してください。 「良い」と「悪い」の2つの評価( 自分の選択 )に制限することができ、1つから5つの星(または1つから10の星)を付けることができます。当然、特定のオブジェクトに対して特定の評価尺度が決定されます: 、引用、コメントはバイナリで評価され、記事と写真は1〜5のスケールで評価されます。



ただし、最終評価の計算方法を決定する必要があります。 バイナリのプラスマイナスの選択では、プラスの数またはマイナスの数の差を最終的な推定値として使用できます。 しかし、あなたはできます-票の総数に対するプラスの数の比率(私の個人的な選択)。 いくつかのオプションの規模のためには、算術平均、調和平均、モード、または中央値を取ることができます。 繰り返しますが、特定のオブジェクトに対して、特定のメソッドを設定します。



一方では評価尺度を決定し、他方では最終評価を計算する方法を決定するクラスは、評価戦略と呼ばれます。 Rating_Strategyインターフェースを紹介しましょう:



 interface Rating_Strategy { /** * @return array of float */ public function getRatingOptions(); /** * @param Rating_Vote_Collection $votes * @return float */ public function getAggregatedOpinion(Rating_Vote_Collection $votes); }
      
      



interface Rating_Strategy { /** * @return array of float */ public function getRatingOptions(); /** * @param Rating_Vote_Collection $votes * @return float */ public function getAggregatedOpinion(Rating_Vote_Collection $votes); }







特定の可能な評価を反映するためにフロートが選択される理由 これにより、個別の評価スケール(オプションを実際のサブセットの整数である整数と比較)と、必要に応じて浮動スケールの両方を反映できます。 最終評点は、整数スケールの場合でも小数にすることができます(たとえば、1〜10のスケールで評価し、評価の算術平均を取る)。 フロートを選択すると、ほぼすべてのオプションをカバーする機会が与えられます。 Rating_Voteクラスの意見フィールドも、それぞれフロートです。



想像のとおり、Rating_Vote_Collectionクラスは、Rating_Voteオブジェクトのコレクション、つまり、特定のオブジェクトに対して受け取った投票のセットを反映しています。 なぜこのクラスが必要なのか、なぜ単にRating_Vote配列を必要としないのか? 消耗品メモリにデータベースからそれらのすべてをダウンロードしていない、と理由 - 投票は多く、数千することができます。 ほとんどの場合、最終評点を取得するには、各オプションの総投票数に関する情報があれば十分です。 したがって、Rating_Vote_Collectionクラスでは、対応するgetOpinionCountsメソッドを作成し、[+ 1→100、-1→50](100“ good”、50“ bad”)の形式の配列を返します。 ただし、重要な戦略(たとえば、投票者のカルマに応じて重みに投票する)を実装する場合は、遅延読み込みも提供します。



評価戦略のいくつかの例:



 abstract class Rating_Strategy_Binary implements Rating_Strategy { const GOOD = +1; const BAD = -1; public function getRatingOptions() { return array(self::GOOD, self::BAD); } } class Rating_Strategy_Binary_Subtraction extends Rating_Strategy_Binary { public function getAggregatedOpinion(Rating_Vote_Collection $votes) { $counts = $votes->getOpinionCounts(); $good = isset($counts[self::GOOD]) ? $counts[self::GOOD] : 0; $bad = isset($counts[self::BAD]) ? $counts[self::BAD] : 0; return $good - $bad; } } class Rating_Strategy_Binary_Rational extends Rating_Strategy_Binary { public function getAggregatedOpinion(Rating_Vote_Collection $votes) { $counts = $votes->getOpinionCounts(); $good = isset($counts[self::GOOD]) ? $counts[self::GOOD] : 0; $bad = isset($counts[self::BAD]) ? $counts[self::BAD] : 0; $total = $good + $bad; return ($total > 0) ? ($good / $total) : 0; } } abstract class Rating_Strategy_Range implements Rating_Strategy { private $min, $max; public function __construct($min, $max) { $this->min = $min; $this->max = $max; } public function getRatingOptions() { return range($this->min, $this->max); } } class Rating_Strategy_Range_Arithmetic extends Rating_Strategy_Range { public function getAggregatedOpinion(Rating_Vote_Collection $votes) { $counts = $votes->getOpinionCounts(); $sum = 0; $total_count = 0; foreach ($counts as $value => $count) { $sum += $value * $count; $total_count += $count; } return ($total_count > 0) ? ($sum / $total_count) : 0; } }
      
      



{ abstract class Rating_Strategy_Binary implements Rating_Strategy { const GOOD = +1; const BAD = -1; public function getRatingOptions() { return array(self::GOOD, self::BAD); } } class Rating_Strategy_Binary_Subtraction extends Rating_Strategy_Binary { public function getAggregatedOpinion(Rating_Vote_Collection $votes) { $counts = $votes->getOpinionCounts(); $good = isset($counts[self::GOOD]) ? $counts[self::GOOD] : 0; $bad = isset($counts[self::BAD]) ? $counts[self::BAD] : 0; return $good - $bad; } } class Rating_Strategy_Binary_Rational extends Rating_Strategy_Binary { public function getAggregatedOpinion(Rating_Vote_Collection $votes) { $counts = $votes->getOpinionCounts(); $good = isset($counts[self::GOOD]) ? $counts[self::GOOD] : 0; $bad = isset($counts[self::BAD]) ? $counts[self::BAD] : 0; $total = $good + $bad; return ($total > 0) ? ($good / $total) : 0; } } abstract class Rating_Strategy_Range implements Rating_Strategy { private $min, $max; public function __construct($min, $max) { $this->min = $min; $this->max = $max; } public function getRatingOptions() { return range($this->min, $this->max); } } class Rating_Strategy_Range_Arithmetic extends Rating_Strategy_Range { public function getAggregatedOpinion(Rating_Vote_Collection $votes) { $counts = $votes->getOpinionCounts(); $sum = 0; $total_count = 0; foreach ($counts as $value => $count) { $sum += $value * $count; $total_count += $count; } return ($total_count > 0) ? ($sum / $total_count) : 0; } }



{ abstract class Rating_Strategy_Binary implements Rating_Strategy { const GOOD = +1; const BAD = -1; public function getRatingOptions() { return array(self::GOOD, self::BAD); } } class Rating_Strategy_Binary_Subtraction extends Rating_Strategy_Binary { public function getAggregatedOpinion(Rating_Vote_Collection $votes) { $counts = $votes->getOpinionCounts(); $good = isset($counts[self::GOOD]) ? $counts[self::GOOD] : 0; $bad = isset($counts[self::BAD]) ? $counts[self::BAD] : 0; return $good - $bad; } } class Rating_Strategy_Binary_Rational extends Rating_Strategy_Binary { public function getAggregatedOpinion(Rating_Vote_Collection $votes) { $counts = $votes->getOpinionCounts(); $good = isset($counts[self::GOOD]) ? $counts[self::GOOD] : 0; $bad = isset($counts[self::BAD]) ? $counts[self::BAD] : 0; $total = $good + $bad; return ($total > 0) ? ($good / $total) : 0; } } abstract class Rating_Strategy_Range implements Rating_Strategy { private $min, $max; public function __construct($min, $max) { $this->min = $min; $this->max = $max; } public function getRatingOptions() { return range($this->min, $this->max); } } class Rating_Strategy_Range_Arithmetic extends Rating_Strategy_Range { public function getAggregatedOpinion(Rating_Vote_Collection $votes) { $counts = $votes->getOpinionCounts(); $sum = 0; $total_count = 0; foreach ($counts as $value => $count) { $sum += $value * $count; $total_count += $count; } return ($total_count > 0) ? ($sum / $total_count) : 0; } }



{ abstract class Rating_Strategy_Binary implements Rating_Strategy { const GOOD = +1; const BAD = -1; public function getRatingOptions() { return array(self::GOOD, self::BAD); } } class Rating_Strategy_Binary_Subtraction extends Rating_Strategy_Binary { public function getAggregatedOpinion(Rating_Vote_Collection $votes) { $counts = $votes->getOpinionCounts(); $good = isset($counts[self::GOOD]) ? $counts[self::GOOD] : 0; $bad = isset($counts[self::BAD]) ? $counts[self::BAD] : 0; return $good - $bad; } } class Rating_Strategy_Binary_Rational extends Rating_Strategy_Binary { public function getAggregatedOpinion(Rating_Vote_Collection $votes) { $counts = $votes->getOpinionCounts(); $good = isset($counts[self::GOOD]) ? $counts[self::GOOD] : 0; $bad = isset($counts[self::BAD]) ? $counts[self::BAD] : 0; $total = $good + $bad; return ($total > 0) ? ($good / $total) : 0; } } abstract class Rating_Strategy_Range implements Rating_Strategy { private $min, $max; public function __construct($min, $max) { $this->min = $min; $this->max = $max; } public function getRatingOptions() { return range($this->min, $this->max); } } class Rating_Strategy_Range_Arithmetic extends Rating_Strategy_Range { public function getAggregatedOpinion(Rating_Vote_Collection $votes) { $counts = $votes->getOpinionCounts(); $sum = 0; $total_count = 0; foreach ($counts as $value => $count) { $sum += $value * $count; $total_count += $count; } return ($total_count > 0) ? ($sum / $total_count) : 0; } }







Rating_RatableインターフェイスにgetRatingStrategyメソッドを追加することは残ります。



 interface Rating_Ratable { /** * @return Rating_Object */ public function asRatingObject(); /** * @return Rating_Strategy */ public function getRatingStrategy(); } class Article extends ActiveRecord implements Rating_Ratable { public function setTableDefinition() { $this->hasReferenceColumn("rating_object_id"); } public function setUp() { $this->hasOne("Rating_Object as rating_object", array("local" => "rating_object_id", "foreign" => "id")); } public function asRatingObject() { return $this->rating_object; } public function getRatingStrategy() { return new Rating_Strategy_Range_Arithmetic(1, 5); } }
      
      







また、Rating_Objectクラスで、関連するRating_Voteを処理するためのメソッドを提供します。



これで、適切な場所に音声を簡単に追加したり、現在の評価を確認したりできます。



 $article->asRatingObject()->addVote($user->asRatingSubject(), 5); echo $article->getRatingStrategy()->getAggregatedOpinion($article->asRatingObject()->getVotes());
      
      






All Articles