桥接模式(Bridge Pattern)将抽象部分与它的实现部分分离,使他们都可以独立地变化。它是一种对象结构型模式,又称为柄体模式或接口模式。
桥接模式包含如下角色。
1.Abstraction(抽象类)
用于定义抽象类的接口,它一般是抽象类而不是接口,其中定义了一个Implementor(实现抽象类)类型的对象并可以维护该对象,它与Implementor之间具有关联关系,它可以包含抽象的业务方法,还可以包含具体的业务方法。
2.RefinedAbstraction(扩充抽象类)
扩充由Abstraction定义的接口,通常情况下它不再是抽象类而是具体类,它实现了在Abstraction中定义的抽象业务方法,在RefinedAbstraction中可以调用Implementor中定义的业务方法。
3.Implementor(实现类接口)
定义实现类的接口,这个接口不一定要与Abstraction的接口完全一致,事实上这两个接口可以完全不同,一般地讲,Implementor接口仅提供基本操作,而Abstraction定义的接口可能会做更多更复杂的操作。Implementor接口对这些基本操作进行了定义,而具体实现交给其子类。通过关联关系,在Abstraction中不仅拥有自己的方法,还可以调用Implementor中定义的方法,使用关联关系来代替继承关系。
4.ConcreteImplementor(具体实现类)
实现Implementor接口并且具体实现它,在不同的ConcreteImplementor中提供基本操作的不同实现,在程序运行时,ConcreteImplementor对象将替代其父类对象,提供给客户端具体的业务操作方法。
1.优点
(1)分离抽象接口及其实现部分。
(2)极大的减少了子类的个数。
(3)提高了系统的可扩展性。
(4)实现细节对客户透明,可以对用户隐藏实现细节。
2.缺点
(1)桥接模式地引入会增加系统的理解与设计难度。
(2)桥接模式要求正确识别出系统中两个独立变化的维度,因此其适用范围具有一定的局限性。
(1)如果一个系统需要在构建的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系
(2)抽象化角色和实现化角色可以以继承的方式独立扩展而互不影响
(3)一个类存在两个独立变化的维度
(4)不希望使用继承或因为多层次继承而导致系统类地个数急剧增加的系统
某软件公司要开发一个跨平台图像浏览系统,要求该系统能够显示BMP、JPG、GIF、PNG等多种格式的文件,并且能够在Windows、Linux、UNIX等多个操作系统上运行。系统首先将各种格式的文件解析为像素矩阵(Matrix),然后将像素矩阵显示在屏幕上,在不同的操作系统中可以调用不同的绘制函数来绘制像素矩阵(变化最大,可考虑成业务实现部分)。另外,系统需具有较好的扩展性,以便在将来支持新的文件格式和操作系统。试使用桥接模式设计该跨平台图像浏览系统。
UML类图:
imp=$imp;
}
public abstract function parseFile($fileName);
}
imp->doPaint($m);
echo $fileName.',格式为bmp。';
}
}
class JPGImage extends Image{
public function parseFile($fileName)
{
$m=new Matrix();
$this->imp->doPaint($m);
echo $fileName.',格式为jpg。';
}
}
class GIFImage extends Image{
public function parseFile($fileName)
{
$m=new Matrix();
$this->imp->doPaint($m);
echo $fileName.',格式为gif。';
}
}
class PNGImage extends Image{
public function parseFile($fileName)
{
$m=new Matrix();
$this->imp->doPaint($m);
echo $fileName.',格式为png。';
}
}
config.txt文件:存储的是数组序列化后的数据 ,使用时反序列化即可,具体看客户端页面
a:2:{s:6:"system";a:3:{i:1;s:5:"Linux";i:2;s:4:"Unix";i:3;s:7:"Windows";}s:11:"file_format";a:4:{i:0;s:3:"PNG";i:1;s:3:"JPG";i:2;s:3:"GIF";i:3;s:3:"BMP";}}
Client.php 写的稍微有点复杂了,因为想把增删改查都弄好。简单的可以只看
$system=new $system();
$fileFormat=$fileFormat.'Image';
$fileFormat=new $fileFormat();
$fileFormat->setImgTmp($system);
$fileFormat->parseFile($fileName);
Client全部代码。
$a){
foreach ($a as $item=>$vv){
if($value=='system'){
echo "$vv".',';
array_push($systemList, $vv);
}
}
}
// print_r($systemList);
echo '增加可用系统请输入add,删除可用系统请输入delete'.PHP_EOL;
echo '请选择系统:';
$system=trim(fgets(STDIN));
//对输入的内容进行规范处理
$system=strtolower($system);//将输入的内容全部转为小写
$system=ucwords($system);//将输入的内容首字母转为大写
$system=str_replace(' ', '', $system);//去掉输入的内容的空格
// echo $system;
if(in_array($system, $systemList)){
//将config文件里的文件格式循环输出,并将文件格式存入数组中
$fileFormatList=[];
echo '目前您可用使用的文件格式:';
foreach ($config as $value=>$a){
foreach ($a as $item=>$vv){
if($value=='file_format'){
echo "$vv".',';
array_push($fileFormatList, $vv);
}
}
}
echo '增加文件格式请输入add,删除文件格式请输入delete'.PHP_EOL;
echo '请选择文件格式:';
$fileFormat=trim(fgets(STDIN));
$fileFormat=strtoupper($fileFormat);//将输入的文件格式全部转为大写
if(in_array($fileFormat, $fileFormatList)){
echo '请输入文件名称:';
$fileName=trim(fgets(STDIN));
$system=$system.'Imp';
$system=new $system();
$fileFormat=$fileFormat.'Image';
$fileFormat=new $fileFormat();
$fileFormat->setImgTmp($system);
$fileFormat->parseFile($fileName);
$this->main();
}elseif ($fileFormat=='ADD'){
echo '请输入您想新增的文件格式名称:';
$fileFormatName=trim(fgets(STDIN));
$this->addFileFormat($fileFormatName,$config,$fileFormatList);
}elseif ($fileFormat=='DELETE'){
echo '请输入您想删除的文件格式名称';
$deleteFileName=trim(fgets(STDIN));
$this->delete($deleteFileName,$config);
}else{
echo '该文件格式暂未存在,是否新增?Y:N';
if(trim(fgets(STDIN))=='Y'){
echo '请输入您想新增的文件格式名称:';
$fileFormatName=trim(fgets(STDIN));
$this->addFileFormat($fileFormatName,$config,$fileFormatList);
}else{
$this->main();
}
}
}else if($system=='Add'){
echo '请输入您想新增的系统名字:';
$systemNew=trim(fgets(STDIN));
if(preg_match("/[\x7f-\xff]/", $systemNew)){
echo '请输入全英文'.PHP_EOL;
$this->main();
}
$systemNew=strtolower($systemNew);//将输入的内容全部转为小写
$systemNew=ucwords($systemNew);//将输入的内容首字母转为大写
$systemNew=str_replace(' ', '', $systemNew);//去掉输入的内容的空格
echo $systemNew;
if(in_array($systemNew, $systemList)){
echo '该系统已经存在'.PHP_EOL;
$this->main();
}else{
$this->addSystem($systemNew,$config);
}
}else if($system=='Delete'){
echo '请输入您想删除的系统名字:';
$deleteName=trim(fgets(STDIN));
$this->delete($deleteName,$config);
}else{
echo '该系统未存在呢,是否新增?Y:N'.PHP_EOL;
if(trim(fgets(STDIN))=='Y'){
echo '请输入您想新增的系统名字:';
$systemNew=trim(fgets(STDIN));
if(preg_match("/[\x7f-\xff]/", $systemNew)){
echo '请输入全英文'.PHP_EOL;
$this->main();
}
$systemNew=strtolower($systemNew);//将输入的内容全部转为小写
$systemNew=ucwords($systemNew);//将输入的内容首字母转为大写
$systemNew=str_replace(' ', '', $systemNew);//去掉输入的内容的空格
if(in_array($systemNew, $systemList)){
echo '该系统已经存在'.PHP_EOL;
$this->main();
}else{
$this->addSystem($systemNew,$config);
}
}else{
$this->main();
}
}
}
//新增系统方法
public function addSystem($systemName,$config){
//1.在config文件中加入新的系统
$config['system'][]=$systemName;
// var_dump($config);
file_put_contents('config.txt',serialize($config));
//2.在ConcreteImplementor.php文件中写入新的方法
$myfile = fopen("ConcreteImplementor.php", "a") or die("Unable to open file!");
$systemNamen=$systemName.'Imp';
$m='$m';
$txt = "
class $systemNamen implements ImgImp{
public function doPaint(Matrix $m)
{
echo '在$systemName 操作系统中显示图像';
}
}";
fwrite($myfile, $txt);
fclose($myfile);
echo '新增系统成功'.PHP_EOL;
$this->main();
}
public function delete($deleteName,$config){
//1.删除config文件中的系统
foreach ($config as $k=>$v){
foreach ($v as $kk=>$vv){
if($vv==$deleteName){
unset($config[$k][$kk]);
$a=true;
}
}
}
file_put_contents('config.txt',serialize($config));
if($a){
echo '删除成功'.PHP_EOL;
$this->main();
}else{
echo '删除失败'.PHP_EOL;
$this->main();
}
}
//新增文件格式方法
public function addFileFormat($fileFormatName,$config,$fileFormatList){
$fileFormatName=strtoupper($fileFormatName);
$fileFormatName=str_replace(' ', '', $fileFormatName);
if(in_array($fileFormatName, $fileFormatList)){
echo '该文件格式已存在'.PHP_EOL;
$this->main();
}else{
//1.将文件格式存入config数组中
$config['file_format'][]=$fileFormatName;
file_put_contents('config.txt',serialize($config));
//2.在RefinedAbstraction.php文件中写入新的方法
$myfile = fopen("RefinedAbstraction.php", "a") or die("Unable to open file!");
$fileFormatNameN=$fileFormatName.'Image';
$fileName='$fileName';
$m='$m';
$b='$this->imp->doPaint($m);';
$txt = "
class $fileFormatNameN extends Image{
public function parseFile($fileName)
{
$m=new Matrix();
$b
echo $fileName.',格式为$fileFormatName';
}
}";
fwrite($myfile, $txt);
fclose($myfile);
echo '新增文件格式成功'.PHP_EOL;
$this->main();
}
}
}
$client=new Client();
$client->main();