建構者模式 (Builder)
建構者模式,主要透過條件堆疊取得產物。
每一個堆疊的步驟,都是一個 Builder,例如透過 set 的方式來傳入 Builder。
實際用途,可運用在設計資料庫查詢器的功能,例如,要查詢一個用戶,名字為 john
例如,以下擷取 Laravel 的查詢器部分程式碼,應該就可清楚了解 Builder 用途:
$name = DB::table('users')->where('name', 'John')->pluck('name');
這裡先列出一些 Builder 程式片段:
<?php
...
class Builder
{
use BuildsQueries, ForwardsCalls, Macroable {
__call as macroCall;
}
/**
* The current query value bindings.
*
* @var array
*/
public $bindings = [
'select' => [],
'from' => [],
'join' => [],
'where' => [],
'having' => [],
'order' => [],
'union' => [],
];
/**
* Set the columns to be selected.
*
* @param array|mixed $columns
* @return $this
*/
public function select($columns = ['*'])
{
$this->columns = is_array($columns) ? $columns : func_get_args();
return $this;
}
...
/**
* Create a new query builder instance.
*
* @param \Illuminate\Database\ConnectionInterface $connection
* @param \Illuminate\Database\Query\Grammars\Grammar|null $grammar
* @param \Illuminate\Database\Query\Processors\Processor|null $processor
* @return void
*/
public function __construct(ConnectionInterface $connection,
Grammar $grammar = null,
Processor $processor = null)
{
$this->connection = $connection;
$this->grammar = $grammar ?: $connection->getQueryGrammar();
$this->processor = $processor ?: $connection->getPostProcessor();
}
...
/**
* Add a join clause to the query.
*
* @param string $table
* @param \Closure|string $first
* @param string|null $operator
* @param string|null $second
* @param string $type
* @param bool $where
* @return $this
*/
public function join($table, $first, $operator = null, $second = null, $type = 'inner', $where = false)
{
$join = $this->newJoinClause($this, $type, $table);
// If the first "column" of the join is really a Closure instance the developer
// is trying to build a join with a complex "on" clause containing more than
// one condition, so we'll add the join and call a Closure with the query.
if ($first instanceof Closure) {
call_user_func($first, $join);
$this->joins[] = $join;
$this->addBinding($join->getBindings(), 'join');
}
// If the column is simply a string, we can assume the join simply has a basic
// "on" clause with a single condition. So we will just build the join with
// this simple join clauses attached to it. There is not a join callback.
else {
$method = $where ? 'where' : 'on';
$this->joins[] = $join->$method($first, $operator, $second);
$this->addBinding($join->getBindings(), 'join');
}
return $this;
}
...
/**
* Get the SQL representation of the query.
*
* @return string
*/
public function toSql()
{
return $this->grammar->compileSelect($this);
}
/**
* Execute a query for a single record by ID.
*
* @param int|string $id
* @param array $columns
* @return mixed|static
*/
public function find($id, $columns = ['*'])
{
return $this->where('id', '=', $id)->first($columns);
}
...
/**
* Set the table which the query is targeting.
*
* @param string $table
* @return $this
*/
public function from($table)
{
$this->from = $table;
return $this;
}
/**
* Handle dynamic method calls into the method.
*
* @param string $method
* @param array $parameters
* @return mixed
*
* @throws \BadMethodCallException
*/
public function __call($method, $parameters)
{
if (static::hasMacro($method)) {
return $this->macroCall($method, $parameters);
}
if (Str::startsWith($method, 'where')) {
return $this->dynamicWhere($method, $parameters);
}
static::throwBadMethodCallException($method);
}
}