设计模式
单例模式
这个类只能创建一个对象。
php的应用主要在于数据库应用,一个应用中会存在大量的数据库操作,使用单例模式,可以避免大量的 new 操作消耗的资源
步骤
构造函数需要标记为private
保存类实例的静态成员变量
-
获取实例的公共的静态方法
class Single { private $name;//声明一个私有的实例变量 private function __construct(){//声明私有构造方法为了防止外部代码使用new来创建对象。 } static public $instance;//声明一个静态变量(保存在类中唯一的一个实例) static public function getinstance(){//声明一个getinstance()静态方法,用于检测是否有实例对象 if(!self::$instance) self::$instance = new self(); return self::$instance; } public function setname($n){ $this->name = $n; } public function getname(){ return $this->name; } }
简单工厂、标准工厂
接口中定义一些方法
实现接口的类实现这些方法
工厂类:用以实例化对象
优点:为系统结构提供了灵活的动态扩展机制。方便维护
/**
* 操作类
* 因为包含有抽象方法,所以类必须声明为抽象类
*/
abstract class Operation{
//抽象方法不能包含函数体
abstract public function getValue($num1,$num2);//强烈要求子类必须实现该功能函数
}
/**
* 加法类
*/
class OperationAdd extends Operation {
public function getValue($num1,$num2){
return $num1+$num2;
}
}
/**
* 减法类
*/
class OperationSub extends Operation {
public function getValue($num1,$num2){
return $num1-$num2;
}
}
/**
* 乘法类
*/
class OperationMul extends Operation {
public function getValue($num1,$num2){
return $num1*$num2;
}
}
/**
* 除法类
*/
class OperationDiv extends Operation {
public function getValue($num1,$num2){
try {
if ($num2==0){
throw new Exception("除数不能为0");
}else {
return $num1/$num2;
}
}catch (Exception $e){
echo "错误信息:".$e->getMessage();
}
}
}
工厂方法
工厂方法模式核心是工厂类不再负责所有对象的创建,而是将具体创建的工作交给子类去做,成为一个抽象工厂角色,它仅负责给出具体工厂类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节
/**
* 工程类,主要用来创建对象
* 功能:根据输入的运算符号,工厂就能实例化出合适的对象
*
*/
class Factory{
public static function createObj($operate){
switch ($operate){
case '+':
return new OperationAdd();
break;
case '-':
return new OperationSub();
break;
case '*':
return new OperationSub();
break;
case '/':
return new OperationDiv();
break;
}
}
}
$test=Factory::createObj('/');
$result=$test->getValue(23,0);
echo $result;
观察者
它是一种事件系统,意味着这一模式允许某个类观察另一个类的状态,当被观察的类状态发生改变的时候,观察类可以收到通知并且做出相应的动作;观察者模式提供了避免组件之间紧密耦合的另一种方法
涉及到两个类:
一个是被观察者
- 添加观察者
- 删除观察者
- 发送通知
一个是观察者
-
做出反应即可
在php中:用户注册(收到邮件,收到短信,或者收到其他信息)
//先定义一个被观察者的接口,这个接口要实现注册观察者,删除观察者和通知的功能。 interface Observables { public function attach(observer $ob); public function detach(observer $ob); public function notify(); } class Saler implements Observables { protected $obs = array(); //把观察者保存在这里 protected $range = 0; public function attach(Observer $ob) { $this->obs[] = $ob; } public function detach(Observer $ob) { foreach($this->obs as $o) { if($o != $ob) $this->obs[] = $o; } } public function notify() { foreach($this->obs as $o) { $o->doActor($this); } } public function increPrice($range) { $this->range = $range; } public function getAddRange() { return $this->range; } }
//定义一个观察者的接口,这个接口要有一个在被通知的时候都要实现的方法
interface Observer
{
public function doActor(Observables $obv);
}
//为了容易阅读,我在这里增加了一层,定义了一个买家, 之后会有Poor和Rich两种不同的类型继承这个类,用以表示不同类型的买家
abstract class Buyer implements Observer
{
}
class PoorBuyer extends Buyer
{
//PoorBurer的做法
public function doActor(observables $obv)
{
if($obv->getAddRange() > 10)
echo '不买了.
';
else
echo '还行,买一点吧.
';
}
}
class RichBuyer extends Buyer
{
//RichBuyer的做法
public function doActor(observables $obv)
{
echo '你再涨我也不怕,咱不差钱.
';
}
}
$saler = new Saler(); //小贩(被观察者)
$saler->attach(new PoorBuyer()); //注册一个低收入的消费者(观察者)
$saler->attach(new RichBuyer()); //注册一个高收入的消费者(观察者)
$saler->notify(); //通知
$saler->increPrice(2); //涨价
$saler->notify(); //通知
官方接口
SplSubject
attach 添加观察者
detach 删除观察者
notify 通知
SplOberser
update 做出响应
SplSubject代表着被观察的对象,其结构:
interface SplSubject{
//添加(注册)一个观察者
public function attach(SplObserver $observer);
//删除一个观察者
public function detach(SplObserver $observer);
//当状态发生改变时,通知所有观察者
public function notify();
}
SplObserver 代表着充当观察者的对象,其结构:
interface SplObserver{
//在目标发生改变时接收目标发送的通知;当关注的目标调用其notify()时被调用
public function update(SplSubject $subject);
}
具体实现
class MyObserver1 implements SplObserver
{
public function update(SplSubject $subject)
{
echo "MyObserver1 updated\n";
}
}
class MyObserver2 implements SplObserver
{
public function update(SplSubject $subject)
{
echo "MyObserver2 updated\n";
}
}
class MySubject implements SplSubject
{
private $_observers;
private $_name;
public function __construct($name)
{
$this->_observers = new SplObjectStorage();
$this->_name = $name;
}
public function attach(SplObserver $observer)
{
$this->_observers->attach($observer);
}
public function detach(SplObserver $observer)
{
$this->_observers->detach($observer);
}
public function notify()
{
foreach ($this->_observers as $observer) {
$observer->update($this);
}
}
public function getName()
{
return $this->_name;
}
}
测试用例
class testDriver
{
public function run()
{
$observer1 = new MyObserver1();
$observer2 = new MyObserver2();
$subject = new MySubject("test");
$subject->attach($observer1);
$subject->attach($observer2);
$subject->notify();
}
}
$test = new testDriver();
$test->run();
适配器
可将一个类的接口转换成客户希望的另外一个接口,使得原本不兼容的接口能够一起工作。通俗的理解就是将不同接口适配成统一的接口
- 你想使用一个已经存在的类,而它的接口不符合你的需求
- 你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类协同工作
- 你想使用一个已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口(仅限于对象适配器)
//目标角色
interface Target {
public function simpleMethod1();
public function simpleMethod2();
}
//源角色
class Adaptee {
public function simpleMethod1(){
echo 'Adapter simpleMethod1'."
";
}
}
//类适配器角色
class Adapter implements Target {
private $adaptee;
function __construct(Adaptee $adaptee) {
$this->adaptee = $adaptee;
}
//委派调用Adaptee的sampleMethod1方法
public function simpleMethod1(){
echo $this->adaptee->simpleMethod1();
}
public function simpleMethod2(){
echo 'Adapter simpleMethod2'."
";
}
}
//客户端
class Client {
public static function main() {
$adaptee = new Adaptee();
$adapter = new Adapter($adaptee);
$adapter->simpleMethod1();
$adapter->simpleMethod2();
}
}
Client::main();
策略模式
策略模式是对象的行为模式,用意是对一组算法的封装。动态的选择需要的算法并使用。
(1)多个类只区别在表现行为不同,可以使用Strategy模式,在运行时动态选择具体要执行的行为。
(2)需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其它方式来实现。
(3)对客户隐藏具体策略(算法)的实现细节,彼此完全独立。
(4)客户端必须知道所有的策略类,并自行决定使用哪一个策略类,策略模式只适用于客户端知道所有的算法或行为的情况。
(5)策略模式造成很多的策略类,每个具体策略类都会产生一个新类。
优点:
1、策略模式提供了管理相关的算法族的办法
2、算法封闭在独立的Strategy类中使得你可以独立于其Context改变它
3、使用策略模式可以避免使用多重条件转移语句
abstract class baseAgent { //抽象策略类
abstract function PrintPage();
}
//用于客户端是IE时调用的类(环境角色)
class ieAgent extends baseAgent {
function PrintPage() {
return 'IE';
}
}
//用于客户端不是IE时调用的类(环境角色)
class otherAgent extends baseAgent {
function PrintPage() {
return 'not IE';
}
}
class Browser { //具体策略角色
public function call($object) {
return $object->PrintPage ();
}
}
$bro = new Browser ();
echo $bro->call ( new ieAgent () );
门面模式
优点
1. 它对客户屏蔽了子系统组件,因而减少了客户处理的对象的数目并使得子系统使用起来更加方便
2. 实现了子系统与客户之间的松耦合关系
3. 如果应用需要,它并不限制它们使用子系统类。因此可以在系统易用性与能用性之间加以选择
适用场景
1. 为一些复杂的子系统提供一组接口
2. 提高子系统的独立性
3.在层次化结构中,可以使用门面模式定义系统的每一层的接口
/**
(1)外观模式(Facade)也叫门面模式,为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
为一些复杂的子系统提供一组接口
(2)主要角色
门面(Facade)角色
• 此角色将被客户端调用
• 知道哪些子系统负责处理请求
• 将用户的请求指派给适当的子系统
子系统(subsystem)角色
• 实现子系统的功能
• 处理由Facade对象指派的任务
• 没有Facade的相关信息,可以被客户端直接调用
• 可以同时有一个或多个子系统,每个子系统都不是一个单独的类,而一个类的集合。每个子系统都可以被客户端直接调用,或者被门面角色调
(3)使用情况 :
首先,在设计初期阶段,应该要有意识将不同的两个层分离,比如经典的三层架构,就需要考虑在数据访问层和业务逻辑层、
业务逻辑层和表示层的层与层之间建立外观Facade,这样可以为复杂的子系统提供一个简单的接口,使得耦合度大大降低。
其次,在开发阶段,子系统往往因为不断的重构演化而变得越来越复杂,大多数的模式使用时也都会产生很多很小的类,这本是好事,
但也给外部调用它们的用户程序带来了使用上的困难,增加外观Facade可以提供一个简单的接口,减少它们之间的依赖。
第三,在维护一个遗留的大型系统时,可能这个系统已经非常难以维护和扩展了,但因为它包含非常重要的功能,新的需求开发必须要依赖于它。
此时,用外观模式Facade也是非常合适的。你可以为新系统开发一个外观Facade类,来提供设计粗糙或高度复杂的遗留代码的比较清晰的简单接口,
让新系统与Facade对象交互,Facade与遗留代码交互所有复杂的工作。”
(4) 具体事例
比如我关机,整个过程包括关闭显示器,关闭pc机器,关闭电源 ,关机的按钮就是门面的角色,其他为子系统
*/
// 门面抽象接口
interface Facade{
public function turnOn() ;
public function turnOff() ;
}
// (1) 关闭显示器
class PcLight {
public function turnOn() {}
public function turnOff() {
echo 'turn off PcLight
' ;
}
}
//(2) pc 机器
class Pcmachine {
public function turnOn() {}
public function turnOff() {
echo 'turn off PcMathion
' ;
}
}
// (3) 关闭电源
class Power {
public function turnOn() {}
public function turnOff() {
echo 'turn off Power
' ;
}
}
// 关机的门面角色
class PcFacade implements Facade{
private $PcLight ;
private $Pcmachine ;
private $Power ;
public function __construct(){
$this->PcLight = new PcLight();
$this->Pcmachine = new Pcmachine();
$this->Power = new Power();
}
// 门面角色的应用
public function turnOff() {
$this->PcLight ->turnOff();
$this->Pcmachine ->turnOff();
$this->Power ->turnOff();
}
public function turnOn() {}
}
// 应用
$button = new PcFacade();
$button ->turnOff();
/* 其实门面模式就是把几个子系统(实例或者类.统一一个统一的接口进行执行,客户端不用关注子系统,只用门面即可 )
DI(Dependency Injection)依赖注入 (Ioc反转控制)
依赖注入
//当一个方法调用的时候,需要依赖于其他对象,才能个完成功能。那么我们就叫这个为依赖注入,也叫翻转控制。
class Son
{
public function cry(Father $father)
{
echo '你看我很不要脸的哭了。
';
$father->baobao();
}
}
class Father
{
public function baobao()
{
echo '很帅很帅的爸爸来抱抱。';
}
}
class Mother
{
public function baobao()
{
echo '很美很美的妈妈来抱抱
';
}
}
$son = new Son();
$father = new Father();
$son->cry($father);
反射
ReflectionClass
反射类对象
ReflectionMethod
反射方法对象
ReflectionParameters
反射参数对象
class UserController
{
public function index(UserModel $user, ArticleModel $article, Session $session)
{
var_dump($user->profile());
var_dump($article->info());
var_dump($session->get());
}
}
class UserModel
{
public function profile()
{
return '查出了用户的属性。';
}
}
class ArticleModel
{
public function info()
{
return '查出来了文章的详情。';
}
}
class Session
{
public function get()
{
return '获取了一个Session';
}
}
/*call_user_func_array(array(new UserController(),'index'),array(new UserModel(),new ArticleModel()));*/
class App
{
static public function run($instance, $method)
{
$r = new ReflectionMethod($instance,$method);
$parameters = $r->getParameters();
$paramObj = [];
foreach ($parameters as $param) {
$class = $param->getClass();
$paramObj[] = new $class->name();
}
call_user_func_array(array($instance,$method),$paramObj);
var_dump($paramObj);
}
}
class Container
{
static public $things = [];
//在容器里取东西
static public function bind($name, Closure $method)
{
if (!isset(self::$things[$name])) {
self::$things[$name] = $method;
}
}
//在容器中放东西
static public function make($name)
{
if(isset(self::$things[$name])){
$func = self::$things[$name];
return $func();
}
}
}
Container::bind('UserModel',function(){
return new UserModel();
});
Container::bind('ArticleModel',function(){
return new ArticleModel();
});
Container::bind('Session',function(){
return new Session();
});
App::run(new UserController(),'index');
MVC
mvc概念
model view controller
psr规范
psr1:基础编程规范
psr2:编码风格规范
psr3:日志接口规范
psr4:自动加载规范
单一入口(简单路由)
简单模式 index.php?m=index&a=index
pathinfo index.php/index/index
spl_autoload_register
__autoload($className)
框架目录架构
app
model
UserModel.php
view
user
login.html
register.html
index
index.html
about.html
controller
Controller.php
UserController.php
IndexController.php
config
config.php
vendor
lib
Model.php
Page.php
Tpl.php
public
css
js
fonts
editor
cache
缓存