感谢@Ryan Vincent,我找到了这个资源 (https://sourcemaking.com/design_patterns/strategy/php) 并稍微改变了策略设计模式。为了避免硬编码的类型值,检查动态类加载是如何在StrategyContext::__construct 方法中完成的。新类实例由$type 变量名启动。类名在 PHP 中应该是 strings,所以这种方式强制类型是 strings 而不仅仅是数字。
与文章中的原始示例不同,我将StrategyContext 附加到书对象并使用策略包装get 方法以更好地使用书对象。
不幸的是,如果业务逻辑以某种方式存在于您的代码中,则您需要对其进行硬编码。使用这种方法,您不需要为每种类型进行硬编码,但您需要为每种类型创建一个策略类。在示例中,我们有 StrategyCaps 、 StrategyStars 和 StrategyExclaim 策略。所以我们的类型仅限于Caps、Stars和Exclaim。
我没有在生产环境中尝试过这段代码,但是您可以通过示例获得一个起点。
同样对于动态加载,你也可以从这个问题中受益。instantiate a class from a variable in PHP?
希望对你有帮助,
<?php
interface StrategyInterface {
public function showTitle($title);
public function showAuthor($author);
}
class StrategyContext implements StrategyInterface {
private $strategy = NULL;
public function __construct($type) {
//Dynamic class loading per type
$classname="Strategy{$type}";
if(class_exists($classname)) {
$this->strategy = new $classname();
} else {
throw new Exception("Strategy not found", 1);
}
}
public function showTitle($title) {
return $this->strategy->showTitle($title);
}
public function showAuthor($author) {
return $this->strategy->showAuthor($author);
}
}
class StrategyCaps implements StrategyInterface {
public function showTitle($title) {
return strtoupper ($title);
}
public function showAuthor($author) {
return strtoupper ($author);
}
}
class StrategyExclaim implements StrategyInterface {
public function showTitle($title) {
return Str_replace(' ','!',$title);
}
public function showAuthor($author) {
return Str_replace(' ','!',$author);
}
}
class StrategyStars implements StrategyInterface {
public function showTitle($title) {
return Str_replace(' ','*',$title);
}
public function showAuthor($author) {
return Str_replace(' ','*',$author);
}
}
class Book {
private $author;
private $title;
private $strategy;
function __construct($strategy, $title_in, $author_in) {
$this->strategy = new StrategyContext($strategy);
$this->author = $author_in;
$this->title = $title_in;
}
function getAuthor() {
return $this->strategy->showAuthor($this->author);
}
function getTitle() {
return $this->strategy->showTitle($this->title);
}
function getAuthorAndTitle() {
return $this->getTitle() . ' by ' . $this->getAuthor();
}
}
writeln('BEGIN TESTING STRATEGY PATTERN');
writeln('');
$type = 'Caps';
$book = new Book($type, 'PHP for Cats','Zeev Suraski');
writeln($book->getAuthorAndTitle());
$type = 'Exclaim';
$book = new Book($type, 'PHP for Unicorns','Rasmus Lerdorf');
writeln($book->getAuthorAndTitle());
$type = 'Stars';
$book = new Book($type, 'PHP for Ponys','Andi Gutmans');
writeln($book->getAuthorAndTitle());
function writeln($line_in) {
echo $line_in.PHP_EOL;
}
更新:
因此,如果您使用 ORM,我们可以假设 Book 是您的模型类。我对 Eloquent 以及它如何处理数据绑定等一无所知,所以我会尽可能简单。所以我假设您可以使用构造函数与数据库中的绑定数据。
将您的StrategyContext 和实际的策略类(您的商务逻辑将在其中编码)作为服务并使用依赖注入,同时找出您将使用的策略。这样,您可以根据 type 变量将所有策略绑定到您的模型对象中。
Book类的更新版本,
class Book {
private $author = "Zeev Suraski";
private $title = "PHP for Cats";
private $strategy;
private $type = 'Caps';
function __construct() {
$this->strategy = new StrategyContext($this->type); //Dependency injection here
}
function getAuthor() {
return $this->strategy->showAuthor($this->author);
}
function getTitle() {
return $this->strategy->showTitle($this->title);
}
function getAuthorAndTitle() {
return $this->getTitle() . ' by ' . $this->getAuthor();
}
function setType($type) {
$this->type = $type;
}
function setStrategy($type=null) {
if($type==null) {
$this->strategy = new StrategyContext($this->type); //Dependency injection here
} else {
$this->strategy = new StrategyContext($type); //Dependency injection here
$this->setType($type);
}
}
}
writeln('BEGIN TESTING STRATEGY PATTERN');
writeln('');
$book = new Book();
writeln($book->getAuthorAndTitle());
$type = 'Exclaim';
$book->setType($type);
$book->setStrategy();
writeln($book->getAuthorAndTitle());
$type = 'Stars';
$book->setStrategy($type);
writeln($book->getAuthorAndTitle());
function writeln($line_in) {
echo $line_in.PHP_EOL;
}