Factor Pattern----工厂模式
一. 概念
工厂模式就是负责生成其他对象的类或方法,就是把创建对象的过程封装起来,这样随时可以产生一个新的对象,减少代码之间耦合。
二. 使用场景(原因)
- 工厂模式可以将对象的生产从直接new 一个对象,改成通过调用一个工厂方法生产。这样的封装,代码若需修改new的对象时,不需修改多处new语句,只需更改生产对象方法。
- 若所需实例化的对象可选择来自不同的类,可省略if-else多层判断,给工厂方法传入对应的参数,利用多态性,实例化对应的类
三. 分类
工厂模式分为:简单工厂模式、工厂方法模式、抽象工厂模式。
- 简单工厂模式,通过静态方法创建对象。可以理解成,只负责生产同一等级结构中的任何一个产品,但是不能新增产品。
- 工厂方法模式,去掉了简单工厂模式中方法的静态属性,使其可以被子类集成,定义一个创建对象的接口,让子类去决定实例化哪个类。可以理解成,用来生产同一等级结构中的固定产品,但是支持增加产品。
- 抽象工厂模式,提供一个创建一系列相关或者相互依赖的对象的接口。可以理解成,用来生产不用类型的全部产品,但是不能增加新品,支持增加新的类型。
三种工厂的区别是,抽象工厂由多条产品线,而工厂方法只有一条产品线,是抽象工厂的简化。而工厂方法和简单工厂相对,大家初看起来好像工厂方法增加了许多代码但是实现的功能和简单工厂一样。但本质是,简单工厂并未严格遵循设计模式的开闭原则,当需要增加新产品时也需要修改工厂代码。但是工厂方法则严格遵守开闭原则,模式只负责抽象工厂接口,具体工厂交给客户去扩展。在分工时,核心工程师负责抽象工厂和抽象产品的定义,业务工程师负责具体工厂和具体产品的实现。只要抽象层设计的好,框架就是非常稳定的。
四. 代码实现
//工厂类 class Factor{ //生成对象方法 static function createDB(){ echo '我生产了一个DB实例'; return new DB; } } //数据类 class DB{ public function __construct(){ echo __CLASS__.PHP_EOL; } } $db=Factor::createDB();
三种工厂模式实现:
//抽象产品 interface Person { public function getName(); } //具体产品实现 class Teacher implements Person { public function getName() { return "老师n"; } } class Student implements Person { public function getName() { return "学生n"; } } //简单工厂 class SimpleFactory { public static function getPerson($type) { $person = null; if ($type == 'teacher') { $person = new Teacher(); } elseif ($type == 'student') { $person = new Student(); } return $person; } } //简单工厂调用 class SimpleClient { function main() { // 如果不用工厂模式,则需要提前指定具体类 // $person = new Teacher(); // echo $person->getName(); // $person = new Student(); // echo $person->getName(); // 用工厂模式,则不需要知道对象由什么类产生,交给工厂去决定 $person = SimpleFactory::getPerson('teacher'); echo $person->getName(); $person = SimpleFactory::getPerson('student'); echo $person->getName(); } } //工厂方法 interface CommFactory { public function getPerson(); } //具体工厂实现 class StudentFactory implements CommFactory { public function getPerson(){ return new Student(); } } class TeacherFactory implements CommFactory { public function getPerson() { return new Teacher(); } } //工厂方法调用 class CommClient { public static function main() { $factory = new TeacherFactory(); echo $factory->getPerson()->getName(); $factory = new StudentFactory(); echo $factory->getPerson()->getName(); } } //抽象工厂模式另一条产品线 interface Grade { function getYear(); } //另一条产品线的具体产品 class Grade1 implements Grade { public function getYear() { return '2016级'; } } class Grade2 implements Grade { public function getYear() { return '2017级'; } } //抽象工厂 interface AbstractFactory { function getPerson(); function getGrade(); } //具体工厂可以产生每个产品线的产品 class Grade1TeacherFactory implements AbstractFactory { public function getPerson() { return new Teacher(); } public function getGrade() { return new Grade1(); } } class Grade1StudentFactory implements AbstractFactory { public function getPerson() { return new Student(); } public function getGrade() { return new Grade1(); } } class Grade2TeacherFactory implements AbstractFactory { public function getPerson() { return new Teacher(); } public function getGrade() { return new Grade2(); } } //抽象工厂调用 class FactoryClient { public function printInfo($factory) { echo $factory->getGrade()->getYear().$factory->getPerson()->getName(); } public static function main() { $client = new FactoryClient(); $factory = new Grade1TeacherFactory(); $client->printInfo($factory); $factory = new Grade1StudentFactory(); $client->printInfo($factory); $factory = new Grade2TeacherFactory(); $client->printInfo($factory); } } //简单工厂 //SimpleClient::main(); //工厂方法 //CommClient::main(); //抽象工厂 FactoryClient::main();
五.使用工厂模式实现运算器
//抽象运算类 abstract class Operation{ abstract public function getVal($i,$j);//抽象方法不能包含方法体 } //加法类 class OperationAdd extends Operation{ public function getVal($i,$j){ return $i+$j; } } //减法类 class OperationSub extends Operation{ public function getVal($i,$j){ return $i-$j; } } //计数器工厂 class CounterFactor { private static $operation; //工厂生产特定类对象方法 static function createOperation(string $operation){ switch($operation){ case '+' : self::$operation = new OperationAdd; break; case '-' : self::$operation = new OperationSub; break; } return self::$operation; } } $counter = CounterFactor::createOperation('+'); echo $counter->getVal(1,2);
缺点:若是再增加一个乘法运算,除了增加一个乘法运算类之外,还得去工厂生产方法里面添加对应的case代码,违反了开放-封闭原则。
解决方法一:通过传入指定类名。
//计算器工厂 class CounterFactor { //工厂生产特定类对象方法 static function createOperation(string $operation){ return new $operation; } } class OperationMul extends Operation{ public function getVal($i,$j){ return $i*$j; } } $counter = CounterFactor::createOperation('OperationMul');
解决方法二:通过抽象工厂模式。
//抽象运算类 abstract class Operation{ abstract public function getVal($i,$j);//抽象方法不能包含方法体 } //加法类 class OperationAdd extends Operation{ public function getVal($i,$j){ return $i+$j; } } //乘法类 class OperationMul extends Operation{ public function getVal($i,$j){ return $i*$j; } } //抽象工厂类 abstract class Factor{ abstract static function getInstance(); } //加法器生产工厂 class AddFactor extends Factor { //工厂生产特定类对象方法 static function getInstance(){ return new OperationAdd; } } //减法器生产工厂 class MulFactor extends Factor { static function getInstance(){ return new OperationMul; } } //文本输入器生产工厂 class TextFactor extends Factor{ static function getInstance(){} } $mul = MulFactor::getInstance(); echo $mul->getVal(1,2);