PHP开发房产广告平台:适配多类型房源与交易的设计模式选型
房产广告交易平台设计模式选型建议
核心问题拆解
你面临的是两个独立变化维度的扩展问题:
- 房源维度:
House/Flat/Garage等,各自有专属字段与行为 - 交易维度:
Buy/BuyNew/Rent/VacationRent/Colocation等,同样有独立的字段与逻辑
直接用继承会导致类爆炸(比如HouseRent/HouseVacationRent...),嵌套判断又会让代码难以维护,所以**桥接模式(Bridge)+ 工厂方法(Factory Method)**是最优组合。
模式选型理由
桥接模式
专门解决多维度独立扩展的耦合问题:
- 将房源(抽象层)和交易类型(实现层)分离,各自独立演进
- 每个房源类只需关联一个交易类型接口,无需关心具体交易逻辑
- 新增房源或交易类型时,只需新增对应类,无需修改现有代码
工厂方法
用来封装具体广告对象的创建逻辑,避免业务代码中出现大量new语句:
- 可以按房源+交易类型的组合,创建对应的广告实例
- 后续扩展新组合时,只需修改工厂类(或新增工厂子类)
PHP代码示例
1. 定义交易类型接口与实现
// 交易类型接口 interface TransactionInterface { public function getDetails(): array; // 其他通用交易方法 } // 购买交易 class Buy implements TransactionInterface { private $price; public function __construct(float $price) { $this->price = $price; } public function getDetails(): array { return ['type' => 'buy', 'price' => $this->price]; } } // 租赁交易 class Rent implements TransactionInterface { private $monthlyRent; private $deposit; private $leaseTerm; public function __construct(float $monthlyRent, float $deposit, int $leaseTerm) { $this->monthlyRent = $monthlyRent; $this->deposit = $deposit; $this->leaseTerm = $leaseTerm; } public function getDetails(): array { return [ 'type' => 'rent', 'monthly_rent' => $this->monthlyRent, 'deposit' => $this->deposit, 'lease_term' => $this->leaseTerm ]; } } // 度假租赁(继承Rent扩展) class VacationRent extends Rent { private $minStayDays; private $peakSeasonSurcharge; public function __construct( float $monthlyRent, float $deposit, int $leaseTerm, int $minStayDays, float $peakSeasonSurcharge ) { parent::__construct($monthlyRent, $deposit, $leaseTerm); $this->minStayDays = $minStayDays; $this->peakSeasonSurcharge = $peakSeasonSurcharge; } public function getDetails(): array { $baseDetails = parent::getDetails(); $baseDetails['type'] = 'vacation_rent'; $baseDetails['min_stay_days'] = $this->minStayDays; $baseDetails['peak_season_surcharge'] = $this->peakSeasonSurcharge; return $baseDetails; } }
2. 定义房源抽象类与子类
// 房源抽象类(桥接的抽象层) abstract class Property { protected $transaction; protected $basicInfo; public function __construct(TransactionInterface $transaction, array $basicInfo) { $this->transaction = $transaction; $this->basicInfo = $basicInfo; } // 获取完整广告信息 public function getAdDetails(): array { return array_merge( $this->getPropertySpecificInfo(), $this->transaction->getDetails() ); } // 子类实现专属房源信息 abstract protected function getPropertySpecificInfo(): array; } // 住宅房源 class House extends Property { private $numberOfBedrooms; private $hasGarden; public function __construct( TransactionInterface $transaction, array $basicInfo, int $numberOfBedrooms, bool $hasGarden ) { parent::__construct($transaction, $basicInfo); $this->numberOfBedrooms = $numberOfBedrooms; $this->hasGarden = $hasGarden; } protected function getPropertySpecificInfo(): array { return array_merge( $this->basicInfo, [ 'property_type' => 'house', 'bedrooms' => $this->numberOfBedrooms, 'has_garden' => $this->hasGarden ] ); } } // 公寓房源 class Flat extends Property { private $floorNumber; private $hasElevator; public function __construct( TransactionInterface $transaction, array $basicInfo, int $floorNumber, bool $hasElevator ) { parent::__construct($transaction, $basicInfo); $this->floorNumber = $floorNumber; $this->hasElevator = $hasElevator; } protected function getPropertySpecificInfo(): array { return array_merge( $this->basicInfo, [ 'property_type' => 'flat', 'floor_number' => $this->floorNumber, 'has_elevator' => $this->hasElevator ] ); } }
3. 工厂类创建广告实例
class PropertyAdFactory { public static function createAd( string $propertyType, string $transactionType, array $propertyParams, array $transactionParams ): Property { // 创建交易实例 $transaction = self::createTransaction($transactionType, $transactionParams); // 创建房源实例 return match($propertyType) { 'house' => new House($transaction, ...$propertyParams), 'flat' => new Flat($transaction, ...$propertyParams), // 新增房源类型时只需加case default => throw new InvalidArgumentException("Unknown property type: $propertyType") }; } private static function createTransaction(string $type, array $params): TransactionInterface { return match($type) { 'buy' => new Buy(...$params), 'rent' => new Rent(...$params), 'vacation_rent' => new VacationRent(...$params), // 新增交易类型时只需加case default => throw new InvalidArgumentException("Unknown transaction type: $type") }; } }
4. 业务代码调用示例
// 创建一个度假租赁的别墅广告 $vacationHouseAd = PropertyAdFactory::createAd( 'house', 'vacation_rent', [['address' => '123 Beach Rd'], 4, true], [1500.0, 3000.0, 6, 7, 0.2] ); // 输出完整广告信息 print_r($vacationHouseAd->getAdDetails());
其他模式排除说明
- 策略模式:更适合单一维度的算法替换,无法解决多维度扩展的类爆炸问题
- 状态模式:用于对象状态转换场景,你的交易类型是固定的业务类型,不是状态变化
- 单纯工厂方法:只能解决对象创建问题,无法解耦房源与交易的耦合关系
内容的提问来源于stack exchange,提问作者Adel taf
相关产品推荐
相关产品推荐

