Я использую фабрику (BillFactory
), чтобы определить, какой Bill
для создания экземпляра. Каждый из Bill
s (AClassBill
, BClassBill
и т. Д.) Может определить, находится ли диапазон данных. В множителе I перебираем по каждому из счетов и проверяем, находятся ли текущие данные в текущем диапазоне Bills. Если его в диапазоне я создаю объект этого класса и верну его.Использование фабрики и полиморфизма
Вот код.
interface IBillable {
function calculate_bill();
}
class Bill implements IBillable {
protected $from;
protected $to;
protected $rate;
protected $unit_amount;
public function get_from() {
return $this->from;
}
public function get_to() {
return $this->to;
}
public function get_rate() {
return $this->rate;
}
public function in_range($unit_amount) {
$_from = $this->get_from();
$_to = $this->get_to();
return ($_from <= $unit_amount && $_to >= $unit_amount);
}
public function calculate_bill() {
return ($this->get_rate() * $this->unit_amount);
}
}
class AClassBill extends Bill {
protected $from = 0;
protected $to = 100;
protected $rate = 3.05;
public function __construct($amount) {
$this->unit_amount = $amount;
}
}
class BClassBill extends Bill {
protected $from = 101;
protected $to = 400;
protected $rate = 4.29;
public function __construct($amount) {
$this->unit_amount = $amount;
}
public function calculate_bill() {
if ($this->unit_amount >= 301) {
return $this->get_rate() * $this->unit_amount;
} else {
$bill1 = $this->get_rate() * ($this->unit_amount - $this->get_from() + 1);
$bill2 = new AClassBill($this->get_from() - 1);
return $bill1 + $bill2->calculate_bill();
}
}
}
class CClassBill extends Bill {
protected $from = 401;
protected $to = -1; // not used
protected $rate = 7.89;
public function __construct($amount) {
$this->unit_amount = $amount;
}
public function in_range($unit_amount) {
$_from = $this->get_from();
return ($_from <= $unit_amount);
}
}
class BillFactory {
private static $s1 = null;
private static $s2 = null;
private static $s3 = null;
public static function instance($units) {
if (is_null(self::$s1))
self::$s1 = new AClassBill(0);
if (is_null(self::$s2))
self::$s2 = new BClassBill(0);
if (is_null(self::$s3))
self::$s3 = new CClassBill(0);
if (self::$s1->in_range($units)) {
$b = new AClassBill($units);
} else if (self::$s2->in_range($units)) {
$b = new BClassBill($units);
} else if (self::$s3->in_range($units)) {
$b = new CClassBill($units);
} else {
$b = false;
}
return $b;
}
}
for ($i = 1; $i <= 500; $i++) {
$b = BillFactory::instance($i);
if ($b !== false) {
printf("%10s\t%04d\t%04.2f\t%04d\t%06.2f\n", get_class($b), $i, $b->get_rate(), $i, $b->calculate_bill());
}
}
Проблема заключается в классе фабрики (BillFactory
). Вы заметите, что я создал 3 фиктивных экземпляра из 3 типов Bill
s (singleton pattern). Вот как я решил свою проблему. Мой вопрос в том, следует ли использовать эти фиктивные экземпляры? Нарушают ли они какой-либо принцип oop?
Другой способ заключается в том, чтобы преобразовать метод in_range
в статический. Тогда мне не нужно создавать экземпляр. Кроме того, поскольку этот метод in_range
является свойством класса (означает, что он не изменяется в разных экземплярах), он должен иметь смысл. В этом случае я должен либо жестко закодировать эти значения в методе in_range
, либо сделать все свойства from
, to
и range
статическими.
Какой подход следует использовать? Вы знаете лучшего?
Просмотрите ваш код. Это отличается от того, о чем вы говорите. Также он выглядит сломанным. – hakre
Также я бы сказал, что вы можете поместить «Range» в свой собственный объект, который, вероятно, уже решает ваш «Проблема». – hakre
со всеми статическими вызовами, я бы сказал, что это более классное программирование, чем oop. – Gordon