提供一个工厂,需要制作啥产品,就传入那个产品的名称就可以产出那个具体的产品对象,无需爆出工厂内部是如何做出这个产品的具体步骤;
比如一个汽车工厂类;你传入宝马他就做出宝马;你传人奔驰他就做出奔驰。
在代码中使用场景:可以是数据库工厂类;或者支付方式工厂类等等。下面以数据库代码讲解一下
<?php
// 定义一个接口
interface Db
{
public function conn();
}
/**
*@class 服务端开发(不知道谁将会被调用)
*
*/
class Dbmysql implements Db{
public function conn() {
echo '连接上了Mysql';
}
}
class Dbsqlite implements Db{
public function conn() {
echo '连接上了sqlite';
}
}
/**
*@class 简单工厂,工厂方法
*
*/
class Factory{
public static function createDb($type = '') {
if($type == 'mysql') {
return new DBmysql();
}elseif($type == 'sqlite') {
return new DBsqlite();
}else{//报错
throw new Exception("Error db type", 1);
}
}
}
/**
*@class 客户端看不到DBbmysql DBsqlite内部细节的,只是知道接口
*/
//只知道服务端开放了一个Factory::createDb()方法
//方法只允许传递数据库名称,如果新增一个oracle需要修改Factory(比较麻烦)
//面向对象设计法则中,重要的开闭原则--对于修改是封闭的,对于扩展是开放的。
$db = Factory::createDb('mysql');
$db = Factory::createDb('sqlite');
$db->conn();
当需要对应的类对象的时候,传入对应的参数即可,但有个问题就是这段代码,如果需要拓展一个oracle数据库呢?是不是又得增加elseif?这样是不是又违背了开闭原则呢?
/**
*@class 简单工厂,工厂方法
*
*/
class Factory{
public static function createDb($type = '') {
if($type == 'mysql') {
return new DBmysql();
}elseif($type == 'sqlite') {
return new DBsqlite();
}else{//报错
throw new Exception("Error db type", 1);
}
}
}
对以上问题就行一下改造。
class Factory
{
public static function create($type)
{
$class = "DB".strtolower($type);
return new $class;
}
}
//通过传入不同的参数来实例化不同的对象;统一在工厂类中进行实例化
$type = 'enhanced';
$cd = Factory::create($type);
$type = 'mysql';
$my_cd = Factory::create($type);
总结:工厂模式挺好玩的,在实际项目中基本每个框架都有它的身影。就是传个参数就把对应类的对象实例化搞出来了!