OOP缩短课程

时间:2016-02-29 12:46:54

标签: php oop

这不是一个关于执行的问题,因为它是关于改进代码的问题。我是一名二年级学生,我们最近开始接触OOP,我终于掌握了它......等等。

我意识到这是一个非常基本的问题,但是从一些最好的方面学到更好的地方。

我的问题

我有一个创建新匹配的类。我的问题是我确信代码不必要很长并且可以得到很大的改进(请记住它是初学者级别)。具体来说我想知道:

  • 我可以将以下内容更改为1个setter和1个getter方法吗?
  • 我想使用rand()函数作为匹配ID,我可以在setMatchId的setter函数中执行此操作,还是应该在类之外完成?

非常感谢您花时间阅读本文。

<?php
class match{
private $matchId;
private $team1;
private $team2;
private $venue; 

function __construct($pMatchId, $pTeam1, $pTeam2, $pVenue){
    $this->matchId = $pMatchId;
    $this->team1 = $pTeam1;
    $this->team2 = $pTeam2;
    $this->venue = $pVenue;
}
    function setMatchId($pMatchId){
        $this->matchId = $pMatchId;

    }

    function getMatchId(){
        return $this->matchId;  

    }
    function setTeam1($pTeam1){
        $this->team1 = $pTeam1; 
    }
    function getTeam1(){
        return $this->team1;    

    }

    function setTeam2($pTeam2){
        $this->team2 = $pTeam2; 
    }
    function getTeam2(){
        return $this->team2;    

    }
    function setVenue($pVenue){
        $this->venue = $pVenue; 

    }
    function getVenue(){
        return $this->venue;    

    }

} // c;lass match

$x = new match("1", "Patriots", "Chargers", "Newlands");
echo $x->getMatchId();
echo'<br />';
echo $x->getTeam1();
echo'<br />';
echo $x->getTeam2();
echo'<br />';
echo $x->getVenue();
?>

7 个答案:

答案 0 :(得分:2)

球队或场地多久换一次比赛?我认为你应该摆脱setter,因为你已经通过构造函数提供了所有必要的数据。

您确实可以将代码更改为使用单个getter和setter方法,但我强烈反对。如果您实现此类方法,IDE将无法帮助您完成代码,但最重要的是,如果没有理由存在,您绝不应盲目地在实体中实现getter和setter。

让设计指导你。首先,通过构造函数传递对象所需的所有内容,并在需要时添加getter / setter,而不是相反。

就ID的随机性而言,您可以使用UUID。您可以使用this library创建它们。我也会通过它的构造函数传递它们。

答案 1 :(得分:1)

第一个问题:

  

我可以将以下内容更改为1个setter和1个getter方法吗?

[编辑]回复第一条评论:

你可以,但是你不应该......对我来说,最好让所有人和所有人分开。在代码中使用match对象实例时,您可能只想获取特定字段。因此,如果您需要获得team1或team2,那么最好使用两种不同的getter方法。

第二个问题:

  

我想使用rand()函数作为匹配ID,我可以在setMatchId的setter函数中执行此操作,还是应该在类之外完成?

嗯,在我看来,处理它的最好方法是禁止任何访问$matchId字段,使其成为私有并删除任何setter方法。 然后,你应该将rand生成放在构造函数中,或者如果你想让它保持在特定的函数中,你可以像这样制作一个公共getter:

public getMatchId(){
    if ($this->matchId != null)
        return $this->matchId

     // Generate it with rand()
     $this->matchId = rand()
     return $this->matchId;
}

在构造函数中,然后只需调用getMatchId()方法。

顺便说一句,这个解决方案并不能帮助你获得一个唯一的匹配标识符,为了达到这个目的,你应该生成它不是纯粹随机的,而是使用依赖于Match信息的东西(例如你可以使用team1team2venue)的组合和/或跟踪使用过的matchid(静态字段或数据库可能会有所帮助)

[编辑]回复第二条评论:

我在getter中使用了if statement,因为这个getter被认为是第一次调用它时生成$matchId,而它始终是$matchId返回之前为其他调用生成的if

你的问题让我想到了另一种可能的实施方式。如果你想避免使用public __construct($team1, $team2, $venue){ $this->matchId = rand(); $this->team1 = $team1; $this->team2 = $team2; $this->venue = $venue } public getMatchId(){ return $this->matchId; } ,那么你应该在构造函数中生成$ matchId。

这种方式应该没问题:

require

答案 2 :(得分:1)

您可以使用PHP的__set__get魔术方法。

private $data = array(); // define property array

public function __set($name, $value) // set key and value in data property
{
    echo "Setting '$name' to '$value'\n";
    $this->data[$name] = $value;
}

public function __get($name)  // get propery value
{
  if(isset($this->data[$name])) {
      return $this->data[$name];
  }
}

您可以按如下方式编写现有代码: -

class Match{

  private $data = [];

  function __construct($property=[]){
    if(!empty($property)){
      foreach($property as $key=>$value){
        $this->__set($key,$value);
      }
    }
  }

  public function __set($name, $value) // set key and value in data property
  {
      // echo "Setting '$name' to '$value'\n";
      $this->data[$name] = $value;
  }

  public function __get($name)  // get propery value
  {
    if(isset($this->data[$name])) {
        return $this->data[$name];
    }
  }

}

使用构造方法设置属性

$x = new match(["matchId"=>"1", "team1"=>"Patriots","team2"=>"Chargers","venue"=>"Newlands"]);
echo '<pre>'; print_r($x);

设置不带构造方法的属性

$x = new match;
$x->matchId = '1'; // 1
$x->team1 = 'team1';  // Patriots
$x->team2 = 'Chargers';  // Chargers
$x->venue = 'Newlands';  // Newlands
echo '<pre>'; print_r($x);

<强>输出: -

Match Object
(
    [data:Match:private] => Array
        (
            [matchId] => 1
            [team1] => Patriots
            [team2] => Chargers
            [venue] => Newlands
        )

)

现在您可以通过以下方式访问和设置属性: -

// Get all properties values
echo $x->matchId; // 1
echo $x->team1;  // Patriots
echo $x->team2;  // Chargers
echo $x->venue;  // Newlands

// Overwrite existing values 
$x->team1 = 'new team1';
// Get updated value
echo $x->team1;  // new team1

希望它会对你有所帮助:)。

答案 3 :(得分:0)

有多个答案涵盖了如何以不同程度的复杂性和魔力进行制定者和吸气剂。在这篇文章中,我宁愿专注于你的班级Match的设计质量。这是基于与你想用什么课程相关的设计理念?

回答这个问题的一些典型陈述:

  • 记录给定的匹配 - 换句话说,它需要保存与一个匹配相关的信息,即venuehomeTeamawayTeamresult?以及可能与某个地方存储结果相关的matchId
  • 设置匹配的结果 - 您将创建匹配,稍后您将设置匹配的实际结果。
  • 存储匹配 - 如果您不将其存储在任何地方,跟踪匹配是徒劳的,所以很可能您需要一些接口到数据库,或者某些意思获取与准备存储到文件或类似文件中的匹配相关的所有信息
  • 能够检索匹配的详细信息 - 如果没有同时获取所有信息,您可以选择获取您想要的特定值的getter。

对我而言,我认为没有必要改变团队或场地,因为这意味着我的世界会有新的比赛。我肯定会实现一个通用的setter,它可以设置任何东西。通用的setter在我的世界中是一种安全风险。

替代实施

坚持给出的陈述,我会写一些类似的东西:

<?php

class Match {
    private $matchId;
    private $homeTeam;
    private $awayTeam;
    private $venue; 
    private $result;

    function __construct($venue, $homeTeam, $awayTeam, $matchId = NULL) {
        $this->venue = $venue;
        $this->homeTeam = $homeTeam;
        $this->awayTeam = $awayTeam;

        if (is_null($matchId)) {
            $this->matchId = uniqid();
        } else {
            $this->matchId = $matchId;
        }
        // In PHP7:   $this->matchId = $matchId ?: uniqid();

        $this->result = "";
    }

    function setResult($result){
        $this->result = $result;
    }

    function getAll(){
        return array($this->venue, $this->homeTeam, $this->awayTeam,
                     $this->matchId, $this->result);  
    }

    function __get($name) {
        if (property_exist($this, $name)) {
            return $this->$name;
        }
    }

    function __set($name, $value) {
        if (property_exist($this, $name)) {
            $this->$name = $value;
    }
} 

?>

与此代码相关的一些评论:

  • homeTeamawayTeam - 变量名team1team2对我来说是一种代码味道。我会为那些人创建一个数组,或者找到更好的名字。在这种情况下,我选择了更好的名称来明确区分这两个变量。
  • __construct() - 创建匹配时,matchId的默认值表示它将设置为uniqid()。我认为这是一种更好的做法,而不是使用随机值。如果你想提供这个,它仍然允许设置一个特定的匹配ID。

    基于您在创建匹配时不知道结果的假设,结果将设置为初学者的空字符串。

  • setResult() - 由于这是匹配的唯一部分,我预见到更改我为此值提供了一个setter。

  • getAll() - 返回所有值的数组,准备存储在某处。如果您愿意,可以轻松将其更改为逗号分隔的字符串或您希望进行后期处理的任何格式。它甚至可能是一本字典,但我只是使用一个简单的数组来保持简单。

  • __get()__set() - 与其他一些答案相反,此getter(和setter)使用起来更安全一些,因为它验证了在此类中定义了实际属性property_exist()

    我不确定我是否真的拥有通用的setter,但是如果你喜欢它,这是一个更好的选择,因为它不允许在运行时为你的类创建新的属性。

的用法

以下是该类的一些简单用法(如果我的未经测试的代码确实有效,那就是):

<!php
    $m = new Match("Newlands", "Patriots", "Chargers");
    // Time passes
    $m->setResult("102-32");

    echo 'In the game ' . $m->homeTeam . ' vs ' . $m->awayTeam
    echo ' at ' . $m ->venue ' the result was ' . $m->result . ' <br />'

    // Append the match to a file
    $fp = fopen('allmatches.csv', 'a');
    fputcsv($fp, $m->getAll());
    fclose($fp);

?>

这使用fputcsv将数组格式化为csv格式的一行。有一个方法或某种方法来创建一个数组匹配是一个练习。您可能有一个静态方法,将文件名作为参数,并返回一个匹配数组。

答案 4 :(得分:0)

当你没有试图解决一个明确定义的问题时,没有好的或坏的模型,就像对一个糟糕的问题没有好的答案一样。

在担心吸气剂和制定者之类的事情之前,您需要确定模型的目的以及它试图解决的问题。

我知道这可能只是一个建模练习,但如果您希望它具有任何价值,请首先定义您的问题域,然后制定解决方案。

例如,如果您正在为允许查询匹配列表的应用程序服务建模,那么Match可能是一个简单的不可变数据结构,充当Data Transfer Object

如果您正在建模一个ViewModel,它意味着双向绑定到CRUD屏幕,允许更新Match的详细信息,那么您可能拥有一个带有公共getter的数据容器和你一样的安装人员。

如果您正在制作锦标赛系统domain model并且有一个用例,例如:“比赛管理员将在比赛结束后输入比赛得分。结果将由系统自动解决。可能的结果主场/客场球队是胜利还是平局。“

那么也许Match会带有诸如(伪代码)之类的行为:

scoring = new Scoring(homeTeamScore: 2, awayTeamScore: 3);
match.complete(scoring);
match.outcome(); //-> MatchOutcome.AwayTeamWon

如您所见,该模型应该是一个明确定义的问题的解决方案。它应该模拟这个问题的现实(不是现实世界),不多也不少。

  

我想使用rand()函数来匹配ID,我可以这样做   在setMatchId的setter函数内部或应该在外部完成   班级?

对于Single Responsibility Principle,实体身份的生成通常不是身份本身的责任。生成身份的算法可以独立于Match概念本身而改变。

答案 5 :(得分:-1)

首先,除非你在一台64kb的RAM机器上进行编码,否则在使用多种get / set方法方面没什么不好的(你可能会用C,Lua等代替PHP) 。如果他们都做了(差不多)相同的事情并且你认为他们正在搞乱代码,那就把它们放在课堂的最后,这样他们就不会阻止你的愿景;-)。

实际更改代码:

如果你有几个成员只有数据不同但实际上代表相同的类型,比如team1,team2将它们放入一个数组并使用get / setByIndex是合法的。

(注意:我没有使用PHP几百年左右,可能会出现语法错误)

示例:

function setTeamByIndex($pIndex, $pTeam){
    $this->teams[$pIndex] = $pTeam; 
}
function getTeamByIndex($pIndex){
    return $this->team[$pIndex];    

}  

或者,在其他语言中,返回多个值是很常见的。这在PHP中是不可能的,但有一个解决方法:

setTeamsFromArray   - 接收带有团队的阵列,并通过他们的密钥应用给定的团队。 getAllTeamsArray   - 返回一个包含所有团队的数组。

function setTeamsFromArray($pTeams){
    foreach ($pTeams as $key=>$team) {
       $this->teams[$key] = $team
    }
}
function getAllTeamsArray(){
     return array( $this->team1, $this->team2 )
} 

echo(getAllTeamsArray()[0]) -> echos team1
echo(getAllTeamsArray()[1]) -> echos team2

在我看来,在您的情况下,这是合情合理的。 缩小的东西并不总是合理的,大多数情况下,10个4线的优于1个40线。

答案 6 :(得分:-3)

对于geter和seter你可以使用__call()魔术方法来实现geters和setter

public function __call($name, $arguments)
{
    // TODO: Implement __call() method.
    $method = substr($name,0,3);
    $key = strtolower(substr($name,3,strlen($name)));
    if($method == 'set') {
        $this->_data[$key] = $argument[0]
        return $this;
    } elseif($method=='get') {
        if(isset($this->_data[$key])) {
            return $this->_data[$key];
        } else {
            return null;
        }
    }
}

这是简单的实现getter和setter自动生成。