我有一个PHP / Laravel最佳实践问题。
以下是该方案: 我有一个带有“type”属性的对象。 type属性将设置为某种整数。
根据对象中的“type”整数,必须执行不同的操作。
处理此对象的最佳方法是什么?我正在拼命想到一种避免使用一大堆if / else语句的方法,因为这种方法感觉非常错误和丑陋。
即。我不想要这个:
if($obj->type == 1) {
//process actions for type 1
}
else if($obj->type == 2){
//process actions for type 2
}
非常感谢任何建议。
谢谢!
答案 0 :(得分:2)
感谢@Ryan Vincent,我找到了这个资源(https://sourcemaking.com/design_patterns/strategy/php),并稍微改变了策略设计模式。为避免硬编码类型值,请检查在StrategyContext::__construct
方法中如何完成动态类加载。新类实例由$type
变量名称启动。 PHP中的类名应为strings
,因此这种方式强制类型strings
不仅仅是数字。
与文章中的原始示例不同,我将StrategyContext
附加到book对象并使用策略包装get方法以更好地使用book对象。
不幸的是,如果业务逻辑将以某种方式存在于您的代码中,则需要对其进行硬编码。使用此方法,您不需要对每种类型进行硬编码,但您需要为每种类型创建一个策略类。在示例中,我们提供了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;
}
答案 1 :(得分:0)
我会使用PHP的switch语句。例如,
switch($obj->type) {
case 1:
// do something
break;
case 2:
// do something else
break;
default:
// default actions
break;
}
这里break
用于停止整个switch语句的执行。如果没有中断,代码执行可能会落到下一个案例中。这有时是令人满意的行为。如果你想要案例1和2运行相同的代码,你可以将案例1留空并在案例2中写下你的所有代码。这样当满足案例1条件时,不会运行与案例1相关的代码,但是如果没有break语句,代码执行将在到达案例2中的break语句之前继续进入案例2。