技术开发 频道

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

  在 Address 对象上调用 format() 方法的代码可能看上去很棒 — 这段代码所做的是使用 Address 类,调用 format() 并完成。相反,Address 类就没那么幸运。它需要了解用于正确格式化的各种格式化方法,这可能使 Address 对象无法被其他人很好地重用,尤其是在其他人没有兴趣在 format() 方法中使用格式化方法类的情况下。虽然使用 Address 的代码没有许多依赖关系,但是 Address 类却有大量代码,而它可能只是一个简单的数据对象。

  Address 类与知道如何格式化 Address 对象的实现类紧密耦合。

  好习惯:在对象之间松散耦合

  在构建优秀的 OO 设计时,必须考虑称为关注点分离(Separation of Concerns,SoC)的概念。SoC 指尝试通过真正关注的内容分离对象,从而降低耦合度。在最初的 Address 类中,它必须关注如何进行格式化。这可能不是优秀的设计。然而,Address 类应当考虑 Address 的各部分,而某种格式化方法应当关注如何正确格式化地址。

  在清单 9 中,格式化地址的代码被移到接口、实现类和工厂中 — 养成 “使用接口” 的习惯。现在,AddressFormatUtils 类负责创建格式化方法并格式化 Address。任何其他对象现在都可以使用 Address 而不必担心要求获得格式化方法的定义。


  清单 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("%s\n%s\n%s, %s %s\n%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");
?>

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

0
相关文章