文章来源refactoringguru.cn/design-patt…
PHP 享元模式讲解和代码示例
享元是一种结构型设计模式, 它允许你在消耗少量内存的情况下支持大量对象。
模式通过共享多个对象的部分状态来实现上述功能。 换句话来说, 享元会将不同对象的相同数据进行缓存以节省内存。
复杂度:******
流行度:******
使用示例: 由于 PHP 语言的特性, 享元模式很少在 PHP 中使用。 PHP 脚本通常仅需要应用的一部分数据, 从不会同时将所有数据载入内存。
识别方法: 享元可以通过构建方法来识别, 它会返回缓存对象而不是创建新的对象。
概念示例
本例说明了享元设计模式的结构并重点回答了下面的问题:
- 它由哪些类组成?
- 这些类扮演了哪些角色?
- 模式中的各个元素会以何种方式相互关联?
了解该模式的结构后, 你可以更轻松地理解下面基于真实世界的 PHP 应用案例。
** index.php: 概念示例
<?php
namespace RefactoringGuru\Flyweight\Conceptual;
/**
* The Flyweight stores a common portion of the state (also called intrinsic
* state) that belongs to multiple real business entities. The Flyweight accepts
* the rest of the state (extrinsic state, unique for each entity) via its
* method parameters.
*/
class Flyweight
{
private $sharedState;
public function __construct($sharedState)
{
$this->sharedState = $sharedState;
}
public function operation($uniqueState): void
{
$s = json_encode($this->sharedState);
$u = json_encode($uniqueState);
echo "Flyweight: Displaying shared ($s) and unique ($u) state.\n";
}
}
/**
* The Flyweight Factory creates and manages the Flyweight objects. It ensures
* that flyweights are shared correctly. When the client requests a flyweight,
* the factory either returns an existing instance or creates a new one, if it
* doesn't exist yet.
*/
class FlyweightFactory
{
/**
* @var Flyweight[]
*/
private $flyweights = [];
public function __construct(array $initialFlyweights)
{
foreach ($initialFlyweights as $state) {
$this->flyweights[$this->getKey($state)] = new Flyweight($state);
}
}
/**
* Returns a Flyweight's string hash for a given state.
*/
private function getKey(array $state): string
{
ksort($state);
return implode("_", $state);
}
/**
* Returns an existing Flyweight with a given state or creates a new one.
*/
public function getFlyweight(array $sharedState): Flyweight
{
$key = $this->getKey($sharedState);
if (!isset($this->flyweights[$key])) {
echo "FlyweightFactory: Can't find a flyweight, creating new one.\n";
$this->flyweights[$key] = new Flyweight($sharedState);
} else {
echo "FlyweightFactory: Reusing existing flyweight.\n";
}
return $this->flyweights[$key];
}
public function listFlyweights(): void
{
$count = count($this->flyweights);
echo "\nFlyweightFactory: I have $count flyweights:\n";
foreach ($this->flyweights as $key => $flyweight) {
echo $key . "\n";
}
}
}
/**
* The client code usually creates a bunch of pre-populated flyweights in the
* initialization stage of the application.
*/
$factory = new FlyweightFactory([
["Chevrolet", "Camaro2018", "pink"],
["Mercedes Benz", "C300", "black"],
["Mercedes Benz", "C500", "red"],
["BMW", "M5", "red"],
["BMW", "X6", "white"],
// ...
]);
$factory->listFlyweights();
// ...
function addCarToPoliceDatabase(
FlyweightFactory $ff, $plates, $owner,
$brand, $model, $color
) {
echo "\nClient: Adding a car to database.\n";
$flyweight = $ff->getFlyweight([$brand, $model, $color]);
// The client code either stores or calculates extrinsic state and passes it
// to the flyweight's methods.
$flyweight->operation([$plates, $owner]);
}
addCarToPoliceDatabase($factory,
"CL234IR",
"James Doe",
"BMW",
"M5",
"red",
);
addCarToPoliceDatabase($factory,
"CL234IR",
"James Doe",
"BMW",
"X1",
"red",
);
$factory->listFlyweights();
** Output.txt: 执行结果
FlyweightFactory: I have 5 flyweights:
Chevrolet_Camaro2018_pink
Mercedes Benz_C300_black
Mercedes Benz_C500_red
BMW_M5_red
BMW_X6_white
Client: Adding a car to database.
FlyweightFactory: Reusing existing flyweight.
Flyweight: Displaying shared (["BMW","M5","red"]) and unique (["CL234IR","James Doe"]) state.
Client: Adding a car to database.
FlyweightFactory: Can't find a flyweight, creating new one.
Flyweight: Displaying shared (["BMW","X1","red"]) and unique (["CL234IR","James Doe"]) state.
FlyweightFactory: I have 6 flyweights:
Chevrolet_Camaro2018_pink
Mercedes Benz_C300_black
Mercedes Benz_C500_red
BMW_M5_red
BMW_X6_white
BMW_X1_red