学习笔记
意图:把对象的实体部分与抽象部分分离开来,分开进行组合封装,使它们可以分别的变化。
主要解决:主要解决的问题是存在多种变化的可能性,而各种的可能性不能通过简单的扩展就可以完成,会造成后续的类的数量爆炸式增多的问题。
实现方式:将一个对象进行分割,将实体部分与抽象部分隔离出来,分别封装。在调用的时候,通过类的多态特性进行聚合调用。
个人理解
合成/聚合复用原则(CARP)中提到,尽量使用合成/聚合,尽量不要使用类的继承。目前开发中主流的观点是高内聚,低耦合,而对象的继承关系本身就是高耦合性的代表,当父类或接口中出现了任何变化,势必会导致子类发生变化。
桥接模式通过将实体与抽象分离的方法,把后期可能会发生改变的抽象功能分离出去,使得实体类不会频繁的发生改变,大大降低了类与类之间的耦合性。这里说明一下,当初开始理解的时候有疑问,如果将抽象功能分离开来,不是将会增加实体类、抽象类两个类直接的耦合性吗,为什么会说降低耦合性呢。原因就在于类的多态特性。我们可以通过参数传递的方式连接两个类,这样就在能保证未来可变的前提下,降低了耦合性。
主要的实现方式是将一个对象分为两个部分,一个部分为实体类(需要对外部提供功能的部分),一个部分为抽象类(对象中存在,但外部不是必须了解知道的部分)。
案例分析
某公司存在三款产品,为了便于统一管理,现需要做一套完整的产品管理统计平台,主要用于多维度统计每个产品的使用情况,目前主要统计每个产品的调用量、每个产品的有效调用等等数据。每个产品的统计均通过不同的接口(各项目组的接口)进行返回。
第一种方案:使用模板模式,创建一个模板抽象类,将可以进行统一处理的方法放在模板抽象类中,将产品中不同的方法放在每个具体的产品类中。问题出现在当后期频繁增加产品、统计方案时,需要维护的代码量大大增加(不仅需要修改抽象模板类,还需要修改每个产品中的方法,而且修改的代码量也会非常多)。
第二种方案:将产品与统计方案割离开,对产品封装一套体系,统计方案为一套体系。现在的问题是,这两套体系中,那个为抽象类,那个为具体类。这个需要分析一下,我们最终需要看到的是什么?是产品吗,显然不是,我们需要看到的是统计数据,所以这里应该以产品作为抽象类体系,统计作为具体类体系。
案例代码
产品体系
<?php
//桥接模式
//产品接口
interface Product
{
public function getProductId();
public function getField();
public function getData();
}
//产品A
class A implements Product {
public function getProductId()
{
return 101;
}
public function getField()
{
return ['Aa', 'Ab', 'Ac'];
}
public function getData()
{
$data = [];
//统计的数据
return $data;
}
}
//产品B
class B implements Product {
public function getProductId()
{
return 102;
}
public function getField()
{
return ['Ba', 'Bb', 'Bc'];
}
public function getData()
{
$data = [];
//统计的数据
return $data;
}
}
//产品C
class C implements Product {
public function getProductId()
{
return 103;
}
public function getField()
{
return ['Ca', 'Cb', 'Cc'];
}
public function getData()
{
$data = [];
//统计的数据
return $data;
}
}
统计体系:
<?php
//统计体系
abstract class Statistics{
private $product;
public function __construct(Product $product)
{
$this->product = $product;
}
protected function getProductData()
{
return $this->product->getData();
}
abstract public function list_data();
abstract public function charts();
}
//折线走势统计图
class ZheXian extends Statistics {
public function list_data()
{
$data = $this->getProductData();
//数据的处理
return [];
}
public function charts()
{
$data = $this->getProductData();
//数据的处理
return '返回的折线图';
}
}
//并状图
class Bing extends Statistics {
public function list_data()
{
$data = $this->getProductData();
//数据的处理
return [];
}
public function charts()
{
$data = $this->getProductData();
//数据的处理
return '饼状图';
}
}
客户端:
//客户端
//获取A的折线统计图
$a = new A();
$zhexian = new ZheXian($a);
//获取B的饼状图
$b = new B();
$bing = new Bing($b);
//C的统计图两个都要
$c = new C();
$c_zhexian = new ZheXian($c);
$c_bing = new Bing($c);
如果需要增加一种统计图,我们只需要增加一个统计图的具体类即可,如果需要增加一款产品,同样的我们只需要增加一个产品类即可,不需要修改过多的类。说白了,无非就是实现了统计与产品的解耦。
UML图
下一篇
初始设计模式——命令模式