在 PHP 中养成 7 个面向对象的好习惯

IBM developerWorks 2008年11月20日 02:47 查看12282次 作者: Nathan A. Good  【
文章分类:项目管理

清单 9. 在对象之间松散耦合的好习惯
<?php

interface AddressFormatter
{
public function format($addressLine1, $addressLine2, $city, $state,
$postalCode, $country);
}

class MultiLineAddressFormatter implements AddressFormatter
{
public function format($addressLine1, $addressLine2, $city, $state,
$postalCode, $country)
{
return sprintf("%sn%sn%s, %s %sn%s",
$addressLine1, $addressLine2, $city, $state, $postalCode, $country);
}
}

class InlineAddressFormatter implements AddressFormatter
{
public function format($addressLine1, $addressLine2, $city, $state,
$postalCode, $country)
{
return sprintf("%s %s, %s, %s %s %s",
$addressLine1, $addressLine2, $city, $state, $postalCode, $country);
}
}

class AddressFormatUtils
{
public static function formatAddress($type, $address)
{
$formatter = AddressFormatUtils::createAddressFormatter($type);

return $formatter->format($address->getAddressLine1(),
$address->getAddressLine2(),
$address->getCity(), $address->getState(),
$address->getPostalCode(),
$address->getCountry());
}

private static function createAddressFormatter($type)
{
if ($type == "inline") {
$formatter = new InlineAddressFormatter();
} else if ($type == "multiline") {
$formatter = new MultilineAddressFormatter();
} else {
$formatter = new NullAddressFormatter();
}
return $formatter;
}
}

$addr = new Address();
$addr->setAddressLine1("123 Any St.");
$addr->setAddressLine2("Ste 200");
$addr->setCity("Anytown");
$addr->setState("AY");
$addr->setPostalCode("55555-0000");
$addr->setCountry("US");

echo(AddressFormatUtils::formatAddress("multiline", $addr));
echo("n");

echo(AddressFormatUtils::formatAddress("inline", $addr));
echo("n");
?>

当然,缺点是只要使用模式,通常就意味着工件(类、文件)的数量会增加。但是,通过减少每个类中的维护可以弥补这个缺点,甚至在获得正确的可重用性时反而可以减少工件量。







您是橡皮;我是胶水

具有高度内聚力的 OO 设计被集中并组织到相关模块中。了解 “关注点” 对于决定如何紧密地联系函数和类十分重要。

坏习惯:降低内聚力

当设计的内聚力较低 时,它就不能良好地组织类和方法。意大利面条式代码(spaghetti code)一词通常用于描述捆绑在一起并且具有低内聚力的类和方法。清单 10 提供了意大利面条式代码的示例。相对通用的 Utils 类将使用许多不同对象并且有许多依赖关系。它执行很多操作,因而很难实现重用。


清单 10. 降低内聚力的坏习惯
<?php

class Utils
{
public static function formatAddress($formatType, $address1,
$address2, $city, $state)
{
return "some address string";
}

public static function formatPersonName($formatType, $givenName,
$familyName)
{
return "some person name";
}

public static function parseAddress($formatType, $val)
{
// real implementation would set values, etc...
return new Address();
}

public static function parseTelephoneNumber($formatType, $val)
{
// real implementation would set values, etc...
return new TelephoneNumber();
}
}

?>

好习惯:利用高内聚力

高内聚力 指将相互关联的类和方法分组在一起。如果方法和类都具有高度的内聚力,则可以轻松地分解整个组而不影响设计。具有高内聚力的设计将提供降低耦合的机会。清单 11 显示了被较好组织到类中的两个方法。AddressUtils 类将包含用于处理 Address 类的方法,显示了与地址相关的方法之间的高度内聚力。同样地,PersonUtils 将包含专门处理 Person 对象的方法。这两个拥有高度内聚力方法的新类的耦合性都很低,因为可以完全独立地使用。


清单 11. 高内聚力的好习惯
<?php

class AddressUtils
{
public static function formatAddress($formatType, $address1,
$address2, $city, $state)
{
return "some address string";
}

public static function parseAddress($formatType, $val)
{
// real implementation would set values, etc...
return new Address();
}

}

class PersonUtils
{
public static function formatPersonName($formatType, $givenName,
$familyName)
{
return "some person name";
}

public static function parsePersonName($formatType, $val)
{
// real implementation would set values, etc...
return new PersonName();
}
}

?>







限制传播

我经常对我所在的软件团队(我在其中担任技术主管或架构师)的成员提起,OO 语言最大的敌人是复制和粘贴操作。当在缺少预先 OO 设计的情况下使用时,没有任何操作会像在类之间复制代码那样具有破坏性。无论何时,如果想将代码从一个类复制到下一个类中,请停下来并考虑如何使用类层次 结构利用类似功能或相同功能。在大多数情况下,使用优秀设计后,您将会发现完全没有必要复制代码。

坏习惯:不使用类层次结构

清单 12 显示了部分类的简单示例。它们从重复的字段和方法开始 — 从长远来看,不利于应用程序作出更改。如果 Person 类中有缺陷,则 Employee 类中也很可能有一个缺陷,因为看上去似乎实现是在两个类之间复制的。


清单 12. 不使用层次结构的坏习惯
<?php
class Person
{
private $givenName;
private $familyName;
}

class Employee
{
private $givenName;
private $familyName;
}

?>

继承 是一个很难入手的习惯,因为构建正确继承模型的分析通常需要花费大量时间。反过来,使用 Ctrl+C 组合键和 Ctrl+V 组合键构建新实现只需几秒钟。但是省下的这部分时间通常会在维护阶段迅速抵销掉,因为应用程序实际上将花费大量进行维护。

好习惯:利用继承

在清单 13 中,新 Employee 类将扩展 Person 类。它现在将继承所有通用方法并且不重新实现这些方法。此外,清单 13 显示了抽象方法的用法,演示如何将基本功能放入基类中以及如何阻止实现类使用特定函数。


清单 13. 利用继承的好习惯
<?php
abstract class Person
{
private $givenName;
private $familyName;

public function setGivenName($gn)
{
$this->givenName = $gn;
}

public function getGivenName()
{
return $this->givenName;
}

public function setFamilyName($fn)
{
$this->familyName = $fn;
}

public function getFamilyName()
{
return $this->familyName;
}

public function sayHello()
{
echo("Hello, I am ");
$this->introduceSelf();
}

abstract public function introduceSelf();

}

class Employee extends Person
{
private $role;

public function setRole($r)
{
$this->role = $r;
}

public function getRole()
{
return $this->role;
}

public function introduceSelf()
{
echo($this->getRole() . " " . $this->getGivenName() . " " .
$this->getFamilyName());
}
}
?>







考虑使用模式

设计模式指对象和方法的常见交互,并且时间证明它可以解决某些问题。当您考虑使用设计模式时,您就需要了解类之间如何进行交互。它是构建类及其交互操作的简单方法,无需重蹈他人的覆辙,并从经过证明的设计中获益。

坏习惯:一次考虑一个对象

实际上没有适当的代码示例可以演示如何考虑使用模式(尽管有丰富的优秀示例可以显示模式实现)。但是,一般而言,您知道在满足以下条件时一次只能考虑一个对象:

  • 不会提前设计对象模型。
  • 开始编写单一方法的实现,而无需去掉大部分模型。
  • 在交谈中不使用设计模式名而宁愿谈论实现。

好习惯:同时添加模式中形成的对象

一般而言,当您在执行以下操作时就是在考虑使用模式:

  • 提前构建类及其交互操作。
  • 根据模式套用类。
  • 使用模式名,如 Factory、SingletonFacade
  • 去掉大部分模型,然后开始添加实现。






结束语

在 PHP 中养成良好的 OO 习惯将帮助您构建更稳定、更易于维护和更易于扩展的应用程序。记住:

  • 保持谨慎。
  • 做个好邻居。
  • 避免看到美杜莎。
  • 利用最弱的链接。
  • 您是橡皮,我是胶水。
  • 限制传播。
  • 考虑使用模式。

当您养成并应用这些习惯后,您很可能会惊讶地发现应用程序在质量上的飞跃。



参考资料

学习

获得产品和技术
  • 使用 IBM 试用软件,改进您的下一个开发项目,这些软件可以通过下载或从 DVD 中获得。

  • 下载 IBM 产品评估版 并开始使用来自 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere® 的应用程序开发工具和中间件产品。


讨论


关于作者


Nathan Good 居住在明尼苏达州的双子城。其专职工作是软件开发、软件架构和系统管理。在不编写软件时,他喜欢组装 PC 和服务器、阅读和撰写技术文章,鼓励他的所有朋友转用开源软件。他自己编著以及与他人合著了很多书籍和文章,包括 Professional Red Hat Enterprise Linux 3, Regular Expression Recipes: A Problem-Solution ApproachFoundations of PEAR: Rapid PHP Development

责任编辑:抽烟的蚊子

给文章打分...

平均分:1.9(97 次)

-5 -4 -3 -2 -1 0 1 2 3 4 5
32

顶一下

发表我的见解...

  • 您的大名: 留空为匿名
  • 您的主页:
  • 您的邮箱: