1
\$\begingroup\$

I'm working on figuring out the best way to design this so that it's well organized and it seems like the factory design pattern makes sense.

Updated: What I'm building: - Pricing calculator - There are 4 products each having their own specific pricing rules that vary from user input - The person can choose between 1 product or all products

Should I have a Calculator class to determine product pricing or leave the calculations in each product type?

/*
 * Use Factory Pattern to build objects
 */
class ProductFactory {
 public static function createProduct($type) {
 switch ($type) {
 case 'solution1':
 return new Solution1Product();
 break;
 case 'solution2':
 return new Solution2Product();
 break;
 case 'solution3':
 return new Solution3Product();
 break;
 case 'solution4':
 return new Solution4Product();
 break;
 }
 }
}
/*
 * Abstract Product
 */
abstract class AbstractProduct {
 protected $price;
 protected $max_limit;
 protected $max_amount;
 abstract public function calculatePrice($dob, $gender, $amount);
}
/*
 * Solution 1 Product
 */
class Solution1Product extends AbstractProduct {
 protected $max_limit = 50000;
 function __contruct() {
 print "Test";
 return "Solution1";
 }
 function calculatePrice($dob, $gender, $amount) {
 $rate = 1.03;
 $price = 55;
 if ($amount >= $this->max_limit) {
 return "Max Limit Reached";
 }
 //@TODO go lookup price from tables
 $this->price = $rate * $price;
 return $this->price;
 }
}
$solution1 = ProductFactory::createProduct('solution1');
print $solution1->calculatePrice("02/25/1982", "male", 100000);
asked Jul 9, 2013 at 14:15
\$\endgroup\$
7
  • 1
    \$\begingroup\$ I love the return; break; combos. I always do that too. I type case ...: and break; and then anything in between. But I always have a default: break; too :) \$\endgroup\$ Commented Jul 9, 2013 at 20:16
  • \$\begingroup\$ default, yes will be adding that one :) In terms of the ProductFactory - I think I've changed my thinking on this. Where Solution1Product would be the actual product - to be more of a type of product. Eg: BookProduct - book would have price, isbn, author, etc, etc. \$\endgroup\$ Commented Jul 10, 2013 at 13:36
  • \$\begingroup\$ Isn't it nice :) $classname = ucfirst( strtolower( $type ) )."Product"; if ( class_exists( $classname ) ) { return new $classname; } \$\endgroup\$ Commented Jul 10, 2013 at 21:10
  • \$\begingroup\$ you have a Procutfactory that creates Solutions? hmm... Personally I think you are looking at the problem the wrong way. I'll try and get an answer by this evening \$\endgroup\$ Commented Jul 12, 2013 at 10:12
  • 1
    \$\begingroup\$ "return ...; break;" simply doesn't make any sense. Adding a "default:" on the other hand would make sense. \$\endgroup\$ Commented Jul 12, 2013 at 18:26

1 Answer 1

2
\$\begingroup\$

Flexible approach

  1. First defining an ultimate abstraction of the factory
  2. Implement it with product type - class mapping
  3. Creating an entry point to register and use the factory

    interface IProductFactory {
     function createProduct($type);
    }
    class DefaultProductFactory implements IProductFactory {
     private $_mappings;
     public function __construct(array $mappings = array()) {
     $this->_mappings = $mappings;
     }
     public function addMappings(array $mappings) {
     $this->_mappings = array_merge($this->_mappings, $mappings);
     }
     public function createProduct($type) {
     if (!isset($this->_mappings[$type])) {
     throw new \Exception("Cannot create product of type " . $type);
     }
     $class = $this->_mappings[$type];
     //can be passed to a DI container to instantiate if needed
     return new $class();
     }
    }
    class ProductFactory {
     private static $_factory;
     public static function setCurrent(IProductFactory $factory) {
     $this->_factory = $factory;
     }
     public static function getCurrent() {
     return $this->_factory;
     }
    }
    ProductFactory::setCurrent(new DefaultProductFactory(array(
     "solution1" => "Solution1Product",
     "solution2" => "Solution2Product",
     "solution3" => "Solution3Product",
     "solution4" => "Solution4Product",
     "solution5" => "\\\\In\\\Some\\\\Other\\\\Namespace\\\\Solution5Product",
     )));
    $solution1 = ProductFactory::getCurrent()->createProduct('solution1');
    print $solution1->calculatePrice("02/25/1982", "male", 100000);
    
answered Nov 2, 2013 at 6:22
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.