我在php类中添加了一些代码,它有几个函数,重复代码我想重构。功能如下所示:
from lxml import html
tree = html.fromstring("""<html>
<head>
<link rel="stylesheet">
</head>
<body>
<b>Old car</b><br>
<sup>13</sup>CO <font color="red">v = 0</font><br>
ID: 02910<br>
<p>
<p><b>CDS</b></p>""")
print tree.xpath("//b/text()")[0] # "Old cars"
我现在需要添加一个完全相同但新代码的新函数。
以下是我想到的事情:
这是什么样的正确模式?
更新:
以下是具有实际代码的两个功能。它们是Symfony2表单处理程序,用于为对象添加上传的图像
public function similarName($arg1, $arg2, $differentObject)
{
// $arg1 and $arg2 are common to all functions
if ($firstCheck) {
// some code
if($secondCheck) {
// some code
if ($thirdCheck) {
// unique code with $differentObject
}
}
}
// return statement
}
答案 0 :(得分:1)
答案可能是将“唯一代码”移动到不同的对象类,如果它仅取决于对象类型。
如果它取决于对象类型以外的因素,那么确实一个好的方法是“回调”
private function commonFunction($arg1, $arg2, $differentObject, $uniqueCallback)
{
// $arg1 and $arg2 are common to all functions
if ($firstCheck) {
// some code
if($secondCheck) {
// some code
if ($thirdCheck) {
$uniqueCallback($differentObject);
}
}
}
// return statement
}
public function similarFunction($arg1, $arg2, $differentObject)
{
$this->commonFunction($arg1, $arg2, $differentObject,
function($differentObject) {
// uniqueCode
});
}
答案 1 :(得分:1)
如果不确切知道您的数据代表什么,很难建议您。
如果所有函数的args相同,并且在uniqueCode
操作之前对它们执行某些操作,那么创建一个将args作为参数并将检查作为方法的对象会更好?
换句话说,uniquecode
似乎是你职能的核心。保持可见和可读,并重构验证部分。
类似的东西:
class ValidateArgs {
private $arg1;
private $arg2;
public function __construct($arg1, $arg2) {
$this->arg1 = $arg1;
$this->arg2 = $arg2;
}
public function check() {
//Check
$check = $this->arg1 && $this->arg2;
return $check;
}
}
然后你会这样称呼:
public function similarName($arg1, $arg2, $differentObject)
{
$validation = new ValidateArgs($arg1, $arg2);
if($validation->check()) {
// unique code goes here
return $result_of_unique_code;
}
}
更新:
看到你的代码示例后,我相信你需要多次迭代才能成功重构它。慢慢地一步一步,试着让代码在每一步都更清洁。
以下是一些建议:
简化if / else结构。有时您可以完全避免使用else
部分。例如,您可以检查$request->getMethod()
并立即返回:
if ($request->getMethod() != 'POST') {
return false;
}
//Rest of the code
count($errorList)
验证似乎仅依赖于data['file']
。我想你可以创建一个具有所有逻辑的函数。像这样:
public function constrainValidations($data) {
$imageConstraint = new \Symfony\Component\Validator\Constraints\Image();
$imageConstraint->maxSizeMessage = Image::ERROR_MESSAGE;
$imageConstraint->maxSize = Image::MAX_SIZE;
$errorList = $this->validator->validateValue($data['file'], $imageConstraint);
if (count($errorList) == 0) {
return true;
} else {
return false;
}
}
然后你的原始代码开始变得更加干净和可读:
if ($request->getMethod() != 'POST') {
return false;
}
if (!$this->constrainValidations($data)) {
return false;
}
//Unique code goes here
return true;
继续一步一步地做。试图取消所有if语句。
此外,这将使您可以更改return
语句并开始抛出异常。
然后你可以开始考虑对象方法以获得额外的可读性。
我个人会避免任何涉及回调的解决方案,但这只是一种品味问题。
答案 2 :(得分:1)
好问题。
基于这两个例子,似乎Post和Event类都应该实现一种“ImageSource”接口。如果其他情况类似,并且还假设可以轻松更改Event,Post和其他类,我认为代码应该是这样的。我们调用常用函数“handleImageSource”:
public function handleImageSource(FormInterface $form, Request $request, ImageSource $imgsrc)
{
if ($request->getMethod() == 'POST') {
$form->bind($request);
$data = $form->getData();
$file = $data['file'];
if ($data['file']) {
$imageConstraint = new \Symfony\Component\Validator\Constraints\Image();
$imageConstraint->maxSizeMessage = Image::ERROR_MESSAGE;
$imageConstraint->maxSize = Image::MAX_SIZE;
$errorList = $this->validator->validateValue($file, $imageConstraint);
if (count($errorList) == 0) {
$image = $imgsrc->createImageFromFile($file, $this->imageManager);
} else {
return false;
}
return true;
} else {
return true;
}
}
return false;
}
然后,实现ImageSource接口的每个类都应该有这样的方法。例如,在Event类中:
public function createImageFromFile($file, $imageManager)
{
if (!($image = $this->getImage()) ) {
$image = new ImageEvent();//|| new ImagePost() || etc...
$image->setEvent($this);//|| setPost() || etc...
$image->setFile($file);
$imageManager->saveImage($image);
} else {
$image->setFile($file);
}
$imageManager->createImage($image);
return $image;
}
在其他情况下,或者如果您只想使用“handleToXxxx”方法重构类,我会在每次调用之前使用不同的代码创建一个匿名函数。例如,再次使用Event类:
$image_source = function($file, $imageManager) use ($Event){
if (!($image = $Event->getImage()) ) {
$image = new ImageEvent();//|| new ImagePost() || etc...
$image->setEvent($this);//|| setPost() || etc...
$image->setFile($file);
$imageManager->saveImage($image);
} else {
$image->setFile($file);
}
$imageManager->createImage($image);
return $image;
};
//Then call to the function
$theHandleObj->handleImageSource($form, $request, $image_source);
然后,在“$ theHandleObj”类中:
public function handleImageSource(FormInterface $form, Request $request, callable $imgsrc)
{
if ($request->getMethod() == 'POST') {
$form->bind($request);
$data = $form->getData();
$file = $data['file'];
if ($data['file']) {
$imageConstraint = new \Symfony\Component\Validator\Constraints\Image();
$imageConstraint->maxSizeMessage = Image::ERROR_MESSAGE;
$imageConstraint->maxSize = Image::MAX_SIZE;
$errorList = $this->validator->validateValue($file, $imageConstraint);
if (count($errorList) == 0) {
$image = $imgsrc($file, $this->imageManager);
} else {
return false;
}
return true;
} else {
return true;
}
}
return false;
}
希望这会有所帮助:)