类的自动载入

在PHP5.3以前使用__autoload()函数

 function __autoload(){require 类名
}

最后被废除,因为PHP项目可能有多个框架,如果没有框架定义一个autoload的话,会报出定义冲突的问题

在5.3之后 提出来 spl_autoload_register();

<?phpspl_autoload_register('autoload1');
t1::test();
t2::test();function autoload1($class){require __DIR__.'/'.$class.'.php';
}?>

OOP基本概念

1.抽象:所有类都是对数据的一组操作的抽象。抽象是用来处理复杂性的主要工具,一个问题越复杂,就越需要抽象来解决,PHP提供抽象类,不能被实例化,只能由具体类继承抽象类的接口以及它的所有具体属性。如果一个类至少有一个抽象方法,那么它必然是抽象类

abstract class one{
public $stor;
abstract public function trick($whatever);}

如果一个抽象类中声名了一个抽象方法,那么继承这个父类的各个子类中必须实现这个方法,另外,抽象类也可以只包含具体方法

2.接口:接口也有抽象方法,不过不能和抽象类中那样在接口中包含具体方法和变量(作为抽象性的类外,接口中可以包含具体常量,不过这个是PHP接口的独有特性)

interface IMethod{public function getInfo($info);public function sendInfo($info);public function calculate($first,$second);}

要实现抽象类所用的是extend而实现接口则需要使用implements,在接口中使用常量需要用到“作用域解析操作符”::,允许在类中以及接口实现中存取变量,接口中也可以只包含常量而不包括任何方法,接口中定义的所有方法都必须是公有,这是接口的特性。类中必须实现接口中定义的所有方法,否则会报一个致命错误。类可以实现多个接口,用逗号来分隔多个接口的名称。

接口也可以继承,通过使用extends操作符.

类要实现接口,必须使用和接口中所定义的方法完全一致的方式。否则会导致致命错误.

使用接口常量的一般格式:

$someVariable= InterfaceName::SOME_CONSTANT;

例如:

interface IconnectInfo
{const Host='location';
}
class conSQL implements IconnectInfo
{
private $server =IconnectInfo::Host;}

抽象类和接口区别

1.对接口的继承使用implements,抽象类使用extends.

2.接口中不可以声明变量,但可以声明类常量.抽象类中可以声明各种变量

3.接口没有构造函数,抽象类可以有

4.接口中的方法默认为public,抽象类中的方法可以用public,protected,private修饰

5.一个类可以继承多个接口,但只能继承一个抽象类

类型提示:类似数据类型

 <?php
interface Iproduct{function apples();function oranges();
}class Fruit implements Iproduct
{public function apples(){return 'We have apples'."<br/>";}public function oranges(){return 'We have oranges'."<br/>";}
}class store implements Iproduct
{public function apples(){return 'We not have apples'."<br/>";}public function oranges(){return 'We not have oranges'."<br/>";}
}class User
{public function __construct(){$store=new store();$fruit=new Fruit();$this->doInterface($store);$this->doInterface($fruit); }function doInterface(Iproduct $product){echo $product->apples();echo $product->oranges();}
}$worker=new User();

注:1.在doInterface中,类型识别IProduct能够识别实现IProduct接口的两个类,换句话说,并不是把它们分别识别位一个fruit实例和另一个store实例,而是会识别它们共同的接口Iproduct

2.它会绑定到接口而不是绑定到一个特定的实现,随着程序变得越来越大,只要遵循接口,就可以做任何改变而不会对程序造成破坏,不仅如此,所做的修改也不会与现实实现纠缠不清,不过不能使用(string和int)作为代码提示,可以使用数组、接口、和类作为代码提示

PHP面向对象高级特性

PSR-0规范

命名空间必须和绝对路径一直

类名首字母必须大写

除入口文件外,其他“.php”必须只有一个类

开发符合PSR-0规范的基础框架:

全部使用命名空间

所有PHP文件必须自动载入,不能有include/require

单一入口

index.php:

define('DIR', __DIR__);
include DIR.'/Imooc/Loader.php';
spl_autoload_register('\\Imooc\\Loader::autoload');Imooc\Object::test();
App\Controller\Home\Index::test();

autoload.php:

<?php
namespace Imooc;
class Loader{static function autoload($class){include DIR.'/'.str_replace('\\', "/",$class).'.php';}}
?>

第一个设计模式原则

   按接口而不是按实现来编程,要将变量设置为一个抽象类或者接口数据类型的实例,而不是一个具体实现的实例,如果按照接口编程,可以实现设计与实现解耦合(代码原理同上)

<?php
abstract class IA{//对所有实现都可用的属性protected $value;//所有实现都必须包含以下两种方法abstract protected function giveB();abstract protected function giveC();public function display(){$giveB=$this->giveB();$giveB=(string)$giveB;return "Const:$".$giveB."for".$this->giveC();}
}class N extends  IA
{protected function giveB(){return 210.54;}protected function giveC(){return "M B";}
}class W extends IA
{protected function giveB(){$this->value=210.54/2;return $this->value;}protected function giveC(){return "Rattlesnake Gulch";}
}class C
{public function __construct(){$n=new N;$w=new W;$this->show($n);$this->show($w);}private function show(IA $region){echo $region ->display()."<br/>";}}
$worker=new C();
?>

第二个设计模式原则

有些OOP程序员认为对象重用就等同于继承,一个类可以有大量属性和方法,扩展这个类就可以重用所有那些对象属性,而不是重新编写代码,可以扩展类,再增加必要的新属性和方法,就一切ok,不过最终对于紧密绑定的对象,一味扩展可能造成过度继承,所以第二个原则的前提是:应当优先选择对象组合不是类继承,经过实例可以得出通过组合,客户使用了两个不同的类,结果是一样的,不过,客户必须实例化两个对象而不是一个,所以看似继承更胜一筹,不过在较大的程序中,组合可以避免维护多个继承层次的各个子类,而且还可以避免可能导致的错误例如,父类的改变会逐级向下传递到子类实现,这可能会影响子类使用的某个算法

这并不是说不能使用继承(IS-A关系),实际上,设计模式同事包含有继承和组合(USE-A关系),不过要避免使用继承形成一长串子类、孙子类、增孙子类等,设计模式建议使用浅继承,另外使用多个累的功能,有助于避免紧密绑定,如果一个具体类可能有子类,修改这个类设计可能导致程序崩溃,而浅继承可以避免这个问题

设计模式的组织 

     按照作用划分:

  创建型:就是用来创建对象的模式,对实例化过程的抽象,如果程序越来越依赖组合,就会减少对硬编码实例化的依赖,而更多地依赖于一组灵活的行为,而创建性模式缇欧拱了一些方法来封装系统使用具体类的有关知识,还可以隐藏实例创建和组合的相关信息

  结构型:采用继承来组合接口或实现,这些模式所关心的是组合结构应当保证结构化,具体描述了组合对象来建立新功能的方法

   行为型:绝大多数模式都是,核心是算法和对象之间职责的分配,这些描述的不只是对象或类的模式,还描述了类与对象的通信模式

按照范围划分:

类模式:重点在于类及其子类之间的关系,在24设计模式中,类模式只包括4中,因为类模式关系通过集成建立,而设计模式强调组合而不是集成

对象模式:强调的是可以在运行时改变的对象,因此这些模式具有动态性

模式原则

开闭原则:对扩展开放,对修改关闭

里氏替换原则:所有引用基类的地方必须能透明地使用其子类的对象

<?php
class B{
public $name='1';
}
class S extends B{
public $name='2';
}
function F(B $obj){
//function F(S $obj){echo $obj->name;
}$o1=new B();
$o2=new S();
F($o1); //调用父类没问题
F($o2);//调用子类也没问题才符合里氏替换原则,对参数进行一定的约束,因为PHP是弱语言类型,所以不是特别意义
//父类进行约束后,子类做参数没有问题
?>

注意:子类的所有方法必须在父类中声名,或子类必须实现父类什么的所有方法,根据里氏替换原则为了保证系统的扩展性,在程序中通常使用父类进行定义,如果一个方法只存在于子类中,父类不提供相应的声名,则无法再父类定义的对象中使用该方法,另外,尽量把父类设计为抽象类或接口,让子类继承父类或者实现父类接口并实现在父类中声名的方法,运行时,子类实例替换父类实例,我们可以很方便地扩展系统的功能,同事无须修改原有子类的代码,增加新的功能可以通过增加一个新的子类来实现,原则就是开闭原则的具体实现手段之一

依赖倒置原则:1.高层模块应该依赖低层模块,两者都应该依赖其抽象

2.抽象不应该依赖于细节,细节应该依赖于抽象

3.面向接口编程,而非面向具体实现编程

//经典例子:mysql数据库连接,数据访问抽象层,符合依赖倒置原则,应用层程序算是高层,具体数据驱动算是底层,mysq中间模块算是抽象,可以让我们多种数据库切换基本不需要修改代码
//-------接口
interface DB{function conn();function add();function del();
}
//--------具体实现
class mysql implements Db{}//具体实现
class access implements Db{}//具体实现
//-----------以上是底层
$db=new mysql();//更改的时候时候只需要更改这句
//---------------------以下前端应用,高层
$db->add();
$db->del();
$db->add();
$db->del();

低层模块:一个逻辑的实现由原子逻辑组成,不可分割的原子逻辑就是底层模块

高层模块:底层模块的再组装就是高层模块

抽象:抽象就是指接口或抽象类

细节:细节就是实现类,实现接口或继承抽象类而产生的类就是细节

接口隔离原则:和单一职责思想一致的,不同的是通过这种思想来对接口和抽象大框架进行限制,单一职责首先是对类的具体功能的限制,然后才因此影响到接口,结果是:接口隔离可以对类有一定影响,单一职责也可能会对接口产生影响

定义:一个类对另一个类的依赖应该建立在最小的接口上,当然也不是越小越好,也需要有合理的粒度

图一:类B需要实现方法1、2、3就要实现方法4、5,所以把接口I进行划分

迪米特法则(最少知道原则):如果A类和B类进行信息交互,可以借助第三方C类来负责

例如:租客 A   房东B  中介  C类

组合/聚合复用原则: 聚合:标识整体和部分的关系,标识“含有”,整体由部分组合而成,部分可以脱离整体作为一个独立的个体存在,例如同学聚会

组合:部分组成整体,而且不可分割,部分不能脱离整体而单独存在 例如:人的四肢

目的:组合/聚合和继承是实现复用的两个基本途径。合成复用原则是指尽量使用合成/聚合,而不是使用继承

例如:子类是超类的一个特殊类,而不是超类的一个角色,也就是区分‘Has-A’和'Is-A',只有后者才符合继承关系,前者应该用聚合来描述

子类具有扩展超类的责任,而不是具有置换掉或注销超类的责任,如果一个子类需要大量的置换掉超类的行为,那么这个类就不应该是这个超类的子类

注:IS-A  代表一个类是另外一个类的一种

Has-A代表一个类是另一个类的一个角色,而不是另一个类的特殊种类

组合:如何通过聚合对象来获得比只使用继承更好地灵活性

解耦:如何降低系统中元素间的依赖性

接口的作用:模式和多态

继承是应对变化环境以及上下文设计的有效方式,而然它会限制灵活性,尤其当类承担多重责任的时候

工厂模式:实例化对象,用工厂方法代替new操作,包括工厂方法模式和抽象工厂模式,抽象工厂模式是工厂方法模式的扩展

单例模式:生成一个且只生成一个对象实例的特殊类

注册模式:全局共享和交换对象

简单工厂模式(静态工厂方法模式):属于创建型模式,由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例

工厂方法模式:定义一个创建对象的接口,让子类决定实例化那个类,在简单工厂模式上延伸扩展

抽象工厂模式:功能相关产品的创建,创建相关或依赖对象的家族,而无需明确指定具体类

原型模式:使用克隆来生成对象,通过复制现有的实例来创建新的实例

建造者模式:封装一个复杂对象的构建过程,并可以按步骤构造

1.工厂模式

对象创建有时会成为面向对象设计一个薄弱环节,“针对接口编程,而不是针对实现编程”的原则,就此而言,鼓励在类中使用抽象的超类,这使代码更具有灵活性,可以让你在运行使用从不同的具体子类中实例化对象,但是这样也有副作用,那就是对象的实例被推迟

<?phpif($r['type']=='b'){
//实例化一个bp类
}else if($row['type']=='c'){$product =new Cd();
}else{//实例化一个sp类
}$p->setId($row['id']);

像这样的条件语句在工厂代码中十分常见,尽管我们尝试从项目中消除大量的条件语句,但是生成对象确实需要使用这些语句

简单工厂模式

角色:一共有三个:工厂类、抽象产品类、具体产品类

2.单例模式

全局变量是面向对象程序员遇到的引发bug的主要原因之一,这是因为全局变量将类捆绑于特定的环境,破坏了封装,如果新的程序无法保证一开始就定义了相同的全局变量,那么一个依赖于全局变量的类就无法从一个应用程序中提取出来并应用到新程序中,一旦开始依赖全局变量,那么在某个类库中声名的全局变量和其他地方声名的全局变量迟早发生冲突,但是全局变量冲突并不会产生任何警告,在开发环境你也许根本发现不了任何问题,命名空间一定程度上避免了命名冲突,至少可以将变量的作用域定义在包中,这意味着第三方库与你的系统产生冲突可能性大大降低,即便如此,命名空间内部还是存在命名冲突

经过良好设计的系统一般通过方法调用来传递对象实例

问题:对象应该可以被系统的任何对象使用,对象不应该被储存在会被覆写的全局变量中,系统中不应该超过一个对象,比如Y可以设置对象的一个属性,而Z对象不需要通过其他对象(假设Y和Z都可以访问该对象)可以直接获取该属性的值

实现:保证一个类仅有一个实例,并提供一个访问它的全局访问点

<?php
class p{
private $ps=array();
private static $instance;private function __construct(){}//把构造函数设为private的,目的是为了不被直接实例化
public static function getInstance(){if(empty(self::$instance)){self::$instance=new p();} return self::$instance;}
public function setP($key,$val){$this->ps[$key]=$val;
}
public function getP($key){return $this->ps[$key];
}
//防止克隆
public function __clone(){throw new Exception('Error:禁止克隆');
}}//调用
$p1=p::getInstance();
$p1->setP('name','m');
unset($p1);//移除引用
$p2=p::getInstance();
print $p2->getp("name"); //输出结果还是m  说明属性值没有丢失

说明:对于PHP连接数据库,仅当一个页面需要多次访问数据库的时候避免创建多次连接对象需要单例模式,其他情况下数据库使用单例模式意义不大,因为PHP页面执行完毕会释放掉所有资源

静态方法不能访问普通的对象属性,因为静态的定义,它只能被类而不是对象调用

总结:单例对象和全局变量相比: 坏的一面,都可能被误用,因为单例在系统任何地方都可以被调用,所以它们可能会导致很难调试的依赖关系,如果改变一个单例,那么所有使用该单例的类可能都会受到影响,在这里依赖本身并不是问题,毕竟,我们每次声名一个特定类型参数的方法,也就创建了依赖关系,但是问题是,单例对象的全局化性质可能是开发人员绕过类接口定义的通信路线,当单例被使用时,依赖便会隐藏在方法内部,而并不会出现在方法声名中,这使得系统依赖关系难以追踪,因此需要小心部署单例类

然而,我认为适度地使用单例模式可以改进系统的设计,可以解决在系统传递不必要的对象,在面向对象开发环境中,单例模式就是对于全局变量的改进,

3.工厂方法模式:面向对象设计强调‘抽象类高于实现’,我们尽量一般化而不是特殊化,工厂方法模式解决了当代码专注于抽象类型如何创建对象实例的问题,答案便是用特定的类来处理实例化

问题:比如在CommsManager类中,在代码运行的时候,我们才知道生成的对象类型、需要能够轻松的添加一个产品类型(比如getHeaderText方法)、每个产品类型可定制特定的功能

实现:工厂方法模式把创建者类与要生成的产品类分离开来,创建者是一个工厂类,其中定义了用于生产产品对象的类方法,如果没有提供默认实现,那么就由创建者子类来执行实例化

注:ApptEncoder为抽象产品类,BloggsApptEncoder为具体产品类,CommsManger为抽象工厂类用来约束工厂类的流程规范,BloggsCommsManager为具体工厂类,当调用的时候  $c=BloggsCommsManager::getFooterText();  //选择留给客户端

工厂方法模式非常符合“开闭原则”,当需要增加一个新的产品的时候,我们只需要增加一个具体的产品类和与之对应的具体工厂即可,无需修改原有系统,但是由于每新增一个新产品时,就会增加两个类,这样势必导致系统的复杂度增加,核心是封装类中不变的部分,提取其中个性化善变的部分为独立类,通过依赖注入以达到解耦、复用和方便后期维护扩展的目的

具体案例: 结构角色:

抽象工厂(店面管理流程):欢迎,中间服务,欢迎下次再来

具体工厂(具体门店):具体店面

抽象产品(产品生产流程):准备材料,烹饪,通知前厅做好了

具体产品(上产具体产品):具体准备,具体做多长时间

代码实例:

//食物-抽象产品
abstract class Food{//所有菜肴共同工作abstract function  prepareFood(){}//端给客户function getFood(){echo "亲,你的$this->name做好了";}
}
//具体产品
class Rice extends Food{public $name='米饭';function  prepareFood(){echo "准备所有食物";}function doRice(){echo "蒸米饭";}
}
class Rice2 extends Food{public $name='2店米饭';function  prepareFood(){echo "准备所有食物";}function doRice(){echo "蒸米饭";}
}
//具体产品
class Chicken extends Food{public $name='鸡汤';function  prepareFood(){echo "准备所有食物";}function cookChicken(){echo "炖汤";}
}
//抽象工厂-店面的管理流程
abstract class Factory{function ini(){echo "欢迎";}function orderFood($type){$food=$this->createFood($type);$food->prepareFood();$food->getFood();return $food;}abstract function createFood($type);
}
//具体工厂-A店面
class createA extends  Factory{function createFood($type){if($type=='Rice'){$food=new Rice();}if($type=='Chicken'){$food=new Chicken();}return $food;}
}
//具体工厂-B店面
class createB extends  Factory{function createFood($type){if($type=='Rice'){$food=new Rice2();}return $food;}
}
//调用
$obj=new createA();
$obj->orderFood('Rice');//抽象产品的好处:规范具体产品的生产工序
//具体产品好处:生产细节可以个性化,只要工序按抽象标准生产即可
//抽象工厂用途:统一店面形象,保证具体店面的品种
//具体工厂用户:与客户之间打交道,隐藏背后生产细节
//如果增加新店,很简单,模式成熟,复制其他分店格式即可,具体细节可以改变
?>

4.抽象工厂模式(应用软件中较少用到,基本用于系统软件中):所谓抽象工厂模式就是提供一个接口,用于创建相关或者依赖对象的家族,而不需要明确指定具体类

我们可以创建一个使用标志参数来觉得返回什么对象的单一的make()方法,而不用给每一个工厂方法创建独立的方法,这样的话,类的接口变得更加紧凑,在使用工厂方法时,定了一个清晰的接口并强制所有具体的工厂对象遵循它,而使用单一的make()方法,我们必须在所有的具体创建者中支持所有的产品对象,每个具体创建者都必须实现相同的标志检测(flag test),客户端类无法确定具体的创建者是否可以生产所有的产品,因为make()方法的内部需要对另种情况都进行考虑做出选择

我们可以创建更灵活的创建者,创建者基类可以提供make()方法来保证每个产品家族有一个默认实现,具体子类可以选择性改变这一行为,子类可以实现自己的make()方法并调用,由此决定生成何种对象,这些创建者子类可以自行决定是否在执行自己的make()方法后调用父类的make()方法

5.原型模式:每次添加产品的时候,被迫去创建一个相关的具体创建者,在一个快速增长的系统会包含越来越多的产品,而维护这种关系便会很快让人厌烦,一种避免这种依赖的办法就是使用PHP的clone复制已存在的具体产品,具体产品类本身便成为它们自己生产的基础,这便是原型模式,使用该模式我们可以用组合代替继承,促进代码运行的灵活性,并减少了必须创建的类

当加载了一个TerrainFactory对象,客户端调用getSea()时,返回在初始化时缓存的Sea对象的一个副本,不仅省掉了一些类,而且有了额外的灵活性,如果sea发生改变的话增加了构造方法,那么可以在实例化new TerrainFactory的时候进行修改没如果产品引用引用了其他对象,那么应该事先__clone()方法保证得到的是深复制

工厂模式和单例模式的组合使用:

让面向对象变成更加灵活的模式

组合模式:将一组对象组合为可像单个对象一样被使用的结构

装饰模式:通过在运行合并对象来扩展功能的一种灵活机制,动态的给对象添加新的功能

外观模式:为复杂或多变的系统创建一个简单的接口

1.组合模式:将对象组合树形结构以表示部分-整体的层次结构,组合模式能让客户以一致的方式处理个别对象以及组合对象(将复杂的递归和循环放到封装类里面,然后让客户端调用,像修改配置文件一样简单)

组合之后:

class Army{private $units=array();function addUnit(Unit $unit){array_push($this->units,$unit);}function bombardStrength(){$ret=0;foreach($this->units as $unit){$ret+=$unit->bombardStrength();}return $ret;}}

优点: 1、高层模块调用简单。 2、节点自由增加。

缺点:在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。

使用场景:部分、整体场景,如树形菜单,文件、文件夹的管理。

组合模式参与者:1.客户端  2.抽象组合类(制定操作的语法标准) 3.具体组合类(实现抽象类) 4.叶子类(实现抽象类)

例如:

<?php
//抽象组件  约束-确保处理的一致性
abstract class Component{//添加节点-树枝或树叶abstract function addNode(Component $obj);//删除节点-树枝或树叶abstract function removeNode(Component $obj);//输出节点内容abstract function show($str);
}
//树枝 -组合对象
class Branch extends  Component{public $name='网站导航';public $childNode=array();function __construct($_name){$this->name=$_name;}function addNode(Component $obj){array_push($this->childNode,$obj);}function removeNode(Component $obj){$key=array_search($obj, $this->childNode);unset($this->childNode[$key]);}function show($str=""){echo $this->name."<br>";$str.="l -";foreach ($this->childNode as $k) {echo $str;$k->show($str);}}
}
//树叶
class Leaf extends  Component{public $name='网站导航';function __construct($_name){$this->name=$_name;}function show($str=''){echo $this->name.'<br>';}function addNode(Component $obj){return false;}function removeNode(Component $obj){return false;}
}
//客户端
//echo "12323";
$branch =new Branch('家电类');
$leaf1=new Leaf('风扇');
$leaf2=new Leaf('洗衣机');
$branch->addNode($leaf1);
$branch->addNode($leaf2);
//
$branch->show();
echo "<br>";
$branch2 =new Branch('电脑类');
$branch3 =new Branch('笔记本');
//
$leaf21=new Leaf('台式机');$branch2->addNode($leaf21);
$branch2->addNode($branch3);
$branch2->show();
//
echo "<br>";
$leaf31=new Leaf('华硕');
$leaf32=new Leaf('华为');
$leaf33=new Leaf('华夏');
$branch3->addNode($leaf31);
$branch3->addNode($leaf32);
$branch3->addNode($leaf33);
$branch3->show();//电脑放在家电里面
echo "<br>";
$branch->addNode($branch2);
$branch->show();
?>

4.适配器模式:将一个类的接口转换成客户希望的另一个接口。适配器模式让那些不兼容的类可以一起工作

优点: 1、可以让任何两个没有关联的类一起运行。 2、提高了类的复用。 3、增加了类的透明度。 4、灵活性好。

缺点: 过多地使用适配器,会让系统非常零乱,不易整体进行把握  2.由于 JAVA 、PHP属于单继承,所以至多只能适配一个适配者类,而且目标类必须是抽象类。

已经做了两个数据库的内容,但是因为不一致不能够直接导入和导出,比如excel数据导入mysql,但是字段不一样,这时候就做一个数组(适配器),这个时候导入数据,把数据进行修改做出符合mysql的数据,然后导入到mysql

具体事例:

<?php
class OutLet{public $flag=0;function powerOne(){$this->flag++;}function powerTwo(){$this->flag++;}function powerOn(){if($this->flag==2){echo "充电中....";}else{echo "没插好";}}
}//客户端手机
class XianMi{public $brand='小米手机';//给小米充电function power($obj){$obj->powerOn();}
}$xm=new XianMi();
$p2=new OutLet();
$xm->power($p2);
//小米插入墙上,第一插不进去,及时插进去也不能充电,
//这个时候我们就需要一个适配器,来完成这个功能
//因为更好的实现开闭原则,所以不能轻易修改这两个类
//适配器类  符合开闭原则
class Adapter{private $outlet;function __construct(){$this->outlet=new OutLet();}function powerOn(){$this->outlet->powerOne();$this->outlet->powerTwo();$this->outlet->powerOn();}
}
$xm=new XianMi();
$a=new Adapter();//适配器插入墙上
$xm->power($a);//小米插入usb中
//把小米手机插入适配器中,不让小米手机和墙上插口直接打交道
?>

5.外观模式:隐藏系统的复杂性,并向客户端提供一个客户端可以访问系统的接口。这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性,这种模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用。

优点: 1、减少系统相互依赖。 2、提高灵活性。 3、提高了安全性。

缺点:不符合开闭原则,如果要改东西很麻烦,继承重写都不合适。

使用场景: 1、为复杂的模块或子系统提供外界访问的模块。 2、子系统相对独立。 3、预防低水平人员带来的风险。

<?phpclass s1{static function Day(){echo "日报表";}}class s2{static function Day(){echo "月报表";}}class s2{static function Day(){echo "年报表";}}//假设日月年报表用的地方比较多,把它们放在一起更方便  这个时候用到外观模式class Facade{static function financial_statements(){s1::Day();s2::Day();s3::Day();}}

6.装饰者模式:允许向一个现有的对象添加新的功能,同时又不改变其结构,这种类型的设计模式属于结构型模式

作用:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器模式相比生成子类更为灵活

主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀

解决:将具体功能职责划分,同时继承装饰者模式

优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

缺点:多层装饰比较复杂。

使用场景: 1、扩展一个类的功能。 2、动态增加功能,动态撤销。

例子: 面条 10       西红柿面  12  西红柿鸡蛋面  15     西红柿牛肉鸡蛋面  20

当使用装饰者模式: 面条  10    加鸡蛋  2    加西红柿  3    加牛肉  5

用比继承更灵活的方式动态为对象添加更多功能

代码实例:

<?php
//食物 -抽象产品
abstract class Food{abstract function price();function getDescription(){return $this->description;}
}
//面条-具体产品class Noodle extends  Food{public $description='面条';function price(){return 10; //10元一碗}
}
//抽象装饰者-通过抽象类约束,方便扩展
abstract class Decorator extends  Food{public $food=null;function __construct(Food $_food){$this->food=$_food;  //都要加到面条里面}
}
//具体装饰者
class AddEgg extends Decorator{function getDescription(){return $this->food->getDescription()."这是加了鸡蛋的面";}function price(){return $this->food->price()+2;}
}
$obj=new Noodle(); //只要面条
$obj1=new AddEgg($obj);//加鸡蛋
echo $obj1->price();
echo $obj1->getDescription();
?>

7.代理模式:为其他对象提供一种代理以控制对这个对象的访问

种类:1.保护代理  2.智能指引(例如:PHP引入计数原理)3.远程代理模式 4.虚拟代理(对多线程语言可以延迟加载大对象,JS图片延迟加载算是虚拟代理的思想)

<?php
//原始类
class DB{function query($sql){return $this->conn->query($sql);}
}
//代理类
class Proxy{public $db=null;function __construct(){$this->db=new DB;$this->db->conn=new MYSQLI('localhost','root','root');}function query($sql){if(preg_match('/or/',$sql)){exit('检查有问题');}return $this->db->query($sql);}
}
//客户端
$db=new Proxy();
$rs=$db->query('sql语句');?>

8.观察者模式:定义独享的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新

优点: 1、观察者和被观察者是抽象耦合的。 2、建立一套触发机制。

缺点: 1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

例子:QQ中自己和好友就是一对多的关系,当自己发了一个说说,其他好友都被通知并自动更新 2.淘宝中产品的商家a和b,当产品更新了,都要给他们进行通知并修改 3.新闻页面,一般生产html页面,缓存在桌面,当数据库更新了,都得到一个通知,并修改内容

代码实例:

<?php
//抽象主题
interface Is{function AddServer(Observer $obj);function RemoveServer(Observer $obj);function NotifyServer(); //通知
}
//抽象观察者
interface Observer{function update(Is $s);
}
//具体主题
class Subject implements Is{private $arr=array();private $id=1;private $title='标题';private $content="内容";function AddServer(Observer $obj){array_push($this->arr,$obj);}function RemoveServer(Observer $obj){$keys=array_search($obj, $this->arr);unset($this->arr[$keys]);}function NotifyServer(){foreach($this->arr as $val){$val->update($this);}}function __set($name,$val){$this->$name=$val;
//      var_dump($this->$name);$this->NotifyServer();}function __get($name){return $this->$name;}
}//具体观察者class ObsA implements  Observer{function update(Is $s){echo "<h1>$s->title</h1><hr>";}}//具体观察者class ObsB implements  Observer{function update(Is $s){echo "<h1>$s->title</h1>....<p>$s->content</p><hr>";}}//客户端调用
$a=new ObsA();
$b=new ObsB();
$s=new Subject();
$s->AddServer($a);
$s->AddServer($b);
$s->RemoveServer($a);
$s->title="我的家";
?>

9.策略模式:定义一系列算法,把他们一个个封装起来,并且使它们可以互相替换

策略模式和工厂模式的区别是:工厂模式是把new 对象封装起来,而策略模式是把具体的算法封装起来

例如:会员优惠策略

代码实例:

<?php
/** 策略模式* 会员级别不同优惠幅度不同* *///抽象策略interface Iprice{public function getPrice($price);}//初级会员class J implements Iprice{public function getPrice($price){return $price *0.95;}}//中级会员class J implements Iprice{public function getPrice($price){return $price *0.85;}}class Price{private $member=null;public function __construct($member){$this->member=$member;}public function getPrice($price){return $this->member->getPrice($price); //根据不同对象调用不同getPrice}}//客户端代码如下$buyer=new price(new J());$price=$buyer->getPrice(100);
?>

10.模板方法模式:定义一个操作中的算法骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结果就可以定义该算法的某些步骤

优点: 1、封装不变部分,扩展可变部分。 2、提取公共代码,便于维护。 3、行为由父类控制,子类实现。

缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。

使用场景: 1、有多个子类共有的方法,且逻辑相同。 2、重要的、复杂的方法,可以考虑作为模板方法。

注意事项:为防止恶意操作,一般模板方法都加上 final 关键词

典型案例:模板继承、模板钩子

<?php
//默认模板
abstract class T{public function _header(){echo "我是标题";}public function _body(){echo "我是内容";}public function _Ad(){//钩子  可以作为广告}public final function display(){$this->_header();echo "<br>";$this->_Ad();$this->_body();echo "<br>";echo "<br>";}
}
//默认模板方法,进行局部和全局修改
class A extends  T{public function _header(){echo "我修改了标题";}function _Ad(){echo "A有广告";}
}
class B extends  T{public function _body(){echo "我修改了内容";}
}$a=new A();
$b=new B();$a->display();
$b->display();
?>

11.职责链模式:使多个对象都有机会处理请求,从而避免请求的发送和接受者之间的耦合关系,将这个对象连接成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止

优点: 1、降低耦合度。它将请求的发送者和接收者解耦。 2、简化了对象。使得对象不需要知道链的结构。 3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。 4、增加新的请求处理类很方便。

缺点: 1、不能保证请求一定被接收。 2、系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。 3、可能不容易观察运行时的特征,有碍于除错。

使用场景: 1、有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。 2、在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。 3、可动态指定一组对象处理请求。

典型案例:学生请假 、JS 中的事件冒泡。

请假1天 老师、请假2天班主任、请假五天院长

分析:对学生来说只需要和老师打交道就可以解决问题,这就是避免请求的发送和接受者之间的耦合关系

代码实例

<?php
//抽象处理类
abstract class Handler{public $succes=null;abstract function handle(Student $obj);
}
//老师-具体处理类
class Teacher extends  Handler{//处理方法function handle(Student $obj){if($obj->day<=1){echo "老师批准";}else{//传递给班主任$this->succes->handle($obj);}
}
}//班主任-具体处理
class Tutor extends Handler{function handle(Student $obj){if($obj->day<=3){echo "班主任审批";}else{$this->succes->handle($obj);}}
}
//经常变换的部分,维护链条类
class chain{static function start(){$teacher =new Teacher();$tutro=new Tutor();$teacher->succes=$tutro;return $teacher;}
}
$teacher=Chain::start();//客户端开始
//学生类
class Student{public $name=null;public $day=2;
}
$s=new Student();
$s->name='1';
$s->day=1;//天数
$teacher->handle($s);
?>

大话设计模式12.25-2.19(过年十五天没有更~偷个懒)相关推荐

  1. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十五章:第一人称摄像机和动态索引...

    Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十五章:第一人称摄像机和动态索引 原文:Introduction to 3 ...

  2. JNA珠宝设计大赛2018/19公布十五件入围作品

    由亚洲博闻旗下<JNA>主办的"JNA珠宝设计大赛2018/19"接获来自全球39个国家及地区共2,588份参赛作品.经过评审团的专业评审加上精准的网上评分系统,大赛三 ...

  3. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十五章:第一人称摄像机和动态索引

    代码工程地址: https://github.com/jiabaodan/Direct12BookReadingNotes 学习目标 回顾视景坐标系变换的数学算法: 熟悉第一人称摄像机的功能: 实现第 ...

  4. 【黑金原创教程】【FPGA那些事儿-驱动篇I 】实验二十五:SDHC模块

    实验二十五:SDHC模块 笔者曾经说过,SD卡发展至今已经衍生许多版本,实验二十四就是针对版本SDV1.×的SD卡.实验二十四也说过,CMD24还有CMD17会故意偏移地址29,让原本范围指向从原本的 ...

  5. [大话设计模式C++版] 第12章 牛市股票还会亏钱 —— 外观模式

    源码可以在这里找到 大话设计模式C++版 股民炒股代码 //main.cpp #include <iostream>using namespace std;//股票1 class Stoc ...

  6. 大话设计模式笔记(二十一、二十二、二十三、二十四、二十五、二十六)

    二十一.单例模式(Singleton) 定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点. 1.通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象.一个最好的办法就是 ...

  7. 大话设计模式--Python

    作者:五岳  出处:http://www.cnblogs.com/wuyuegb2312 上一周把<大话设计模式>看完了,对面向对象技术有了新的理解,对于一个在C下写代码比较多.偶尔会用到 ...

  8. 大话设计模式Python实现-简单工厂模式

    简单工厂模式(Simple Factory Pattern):是通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类. 下面使用简单工厂模式实现一个简单的四则运算 1 #!/us ...

  9. 大话设计模式Python实现-观察者模式

    观察者模式(发布-订阅模式 Publish Subscribe Pattern):定义了一种一对多的关系,让多个观察对象同时监听一个主题对象,当主题对象状态发生变化时会通知所有观察者,是它们能够自动更 ...

最新文章

  1. asp.net 对xml文件的读写,添加,修改,删除操作
  2. nginx_lua_waf安装测试
  3. Git Bash命令行基础
  4. pom war jar的区别
  5. linux内核 DebugFS
  6. Atom 编辑器实时预览 HTML 页面
  7. Log4Net简单使用
  8. Toad for Oracle 导入MIP.dmp文件时:报内存不足时的解决办法:
  9. matlab predict函数并行,Matalb 智能算法第29个案例运行报错问题
  10. 电脑图标变成白纸如何恢复
  11. 关于屏保设置不生效时要了解的几个小技巧!
  12. 镜子--天空16度蓝
  13. 不同安卓模拟器连接appium的端口
  14. 用计算机专业怼人,专业示范,教你如何用所学专业知识“怼人”
  15. 台湾最大IC封装厂近三成员工停工14天,安世半导体宣布今日起调涨价格!
  16. 怎么自定义服务器的404,如何自定义404页面
  17. 正向代理和反向代理定义和区别
  18. 智能小区安防子系统实现
  19. 系统设计 架构设计 画图工具 架构图 设计图
  20. 基于链表的贪吃蛇(C语言)

热门文章

  1. JAVA—构造方法和对象的创建
  2. Orbia宣布现金要约收购到期并公布到期日结果
  3. 马铃薯(土豆)播种机设计
  4. 2020武汉大学计算机学院保研夏令营面试
  5. 港科夜闻丨香港科大(广州)获国家教育部批准筹建,南沙校址举办动工仪式...
  6. 1像素下边框引发移动端设备像素比的应用
  7. Canvas清除画布clearRect非常容易踩坑的点
  8. atoi函数_C语言进阶之路:strtod()函数的用法!
  9. Win10 安装系统跳过创建用户,直接启用 Administrator
  10. fcpx插件:PremiumVFX Comic Titles(手绘漫画风格的标题和背景)