面向对象的设计模式及魔术函数
来源:互联网 发布:php编程是什么 编辑:程序博客网 时间:2024/06/01 18:04
1.工厂模式:
a.概述: 工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程(new 关键字和具体的构造器)隐藏起来。用一个工厂方法来替代,对外提供的只是一个工厂方法,达到提高灵活性的目的。
b.优点:
1.隐藏了new关键字和构造器
2.降低了这个对象与别的类之间的耦合度,提高了程序的可扩展性。
原因:当子类被别的类替代,或者构造器的参数发生变化的时候,只需改动工厂方法内的new即可,改动量降到了最低,而如果不用工厂模式,而是直接用new关键字的话,需要改动的地方就很多了
3.把对象的设计和实现分割开来,从而代码扩展性强、灵活性高。
c.工厂模式的使用范围:
当遇到下面的情况时,开发人员可以考虑采用工厂模式:
* 在编码时不能预见需要创建哪一个种类的实例。
* 一个类使用它的子类来创建对象。
* 开发人员不希望创建了那个类的实例以及如何创建实例的信息暴露给外部程序。
除了上面提到的例子,工厂模式的实现方式还允许有一些小小的变化,例如:
* 基类可以是一个抽象类,在这种情况下,工厂类必须返回一个非抽象类。
* 基类提供了一些缺省方法,只有当这些缺省方法不能满足特殊需求的情况下才能在子类中重写这些方法。
* 可以直接通过传递给工厂类的参数决定应该返回哪一个子类的实例。
d. 使用工厂模式,它的设计期于运行期的对象不同,这样就增强了代码的可扩展性。
它把构造器隐藏了起来,降低了代码的耦合度,增强了代码的复用性。
工厂模式与new的比较:如果使用new关键字的话,那么如果这个类的对象在很多的地方用到,必须要使用多次的new操作,这样容易引起代码的重复使用,如果需要改动或者替换成这个类的子类对象,那么,就需要把执行了new操作的所有地方都要改,比较麻烦。而工厂模式,因为它代替了构造器和new关键字,而且,它是使用面向接口的,所以,需要这个类的对象的时候,只需要调用这个方法就可以了,如果,需要改动或者替换成这个类的子类对象。只要修改这个工厂里面的内容,而其他的地方都不需要改动。
工厂模式的结构是:用一个方法来代替new关键字和构造器。
工厂模式相当于创建实例对象的new,经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,工厂模式是现今最常用的模式,在Java程序系统中随处可见。
<?php
class
YunSuan
{
public
$a
;
public
$b
;
//写一个空方法,让子类继承重写父类
public
function
Suan()
{
}
}
class
Jia
extends
YunSuan
{
public
function
Suan()
{
return
$this
->a+
$this
->b;
}
}
//工厂模式
//工厂类:生产对象
class
GongChang
{
static
function
ShengChan(
$ysf
)
{
switch
(
$ysf
)
{
case
"+"
:
return
new
Jia();
break
;
case
"-"
:
return
new
Jian();
break
;
}
}
}
$jia
= GongChang::ShengChan(
"+"
);
$jia
->a = 10;
$jia
->b = 10;
echo
$jia
->Suan();
//结果为20
2. 单例模式:
一、单例模式的四大特征:
懒汉式:
1。声明一个私有的,静态的本类对象,但并不在声明的时候就初始化,因此,它 的值为null。
2。私有化构造器
3。对外提供一个全局的,共有的,静态的,唯一的方法,用来获得该实例,但注意的是:必须要手动保持线程同步(synchronized)
4.在该方法里,判断对象是否为null,如果是null的话,表示这个类还没有被实例化,就会初始化这个对象,再返回如果不是null的话,就直接返回。
饿汉式:
1.声明一个私有的,静态的本类对象,并在声明的时候就初始化
2.私有构造器
3.对外提供一个全局的,共有的,静态的,唯一的方法,用来获得该实例(饿汉式线程本身就是同步的)
4.在该方法里,直接返回该对象即可
从资源利用效率角度来讲,这个比懒汉式单例类稍微差些。从速度和反应时间角度来讲,则比懒汉式单例类稍好些。
二、它能解决什么问题:
它确保一个类在java虚拟机里只有一个实例,使一个类只有一个对象,整个系统共享这个对象。
三、什么时候使用懒汉式和饿汉式:
1。 在使用的几率很少的情况下使用懒汉式。 --用的时候实例
2。 而使用的几率很高的话就用饿汉式。--一开始就初始化实例
四、单例模式的好处:
整个系统中的所有的类共用一个实例化对象,这样可以有效的节省资源。
优点:
1. 改进系统的设计
2. 是对全局变量的一种改进
缺点:
1. 难于调试
2. 隐藏的依赖关系
3. 无法用错误类型的数据覆写一个单例
单例模式的目的是将类只能造一个对象出来
单例模式的主要方法是:将构造 变成私有的-->做一个静态的生成对象的方法-->造一个静态的存储对象-->return 静态的对象
<?php
class
DBDA
{
//连接数据库的类让他只能造一个对象出来,在不加任何控制的时候可以造很多的类出来
//在造对象的时候会调用构造的方法,
//把构造方法变成私有的就可以可以控制住
public
static
$dx
;
//存储对象
//把构造做为私有
private
function
__construct()
{
}
//生成对象
static
function
DuiXiang()
{
if
(
empty
(self::
$dx
))
{
self::
$dx
=
new
DBDA();
//调用静态对象
}
return
self::
$dx
;
}
}
//DBDA::DuiXiang();//调用静态方法
$db
= DBDA::DuiXiang();
面向对象的设计原则:
OOD基本上有6大原则,而实际上都是互补的,也就是说一些原则需要利用另一些原则来实现自己。6大原则如下:
1) Open-Close Principle(OCP),开-闭原则,讲的是设计要对扩展有好的支持,而对修改要严格限制。这是最重要也是最为抽象的原则,基本上我们所说的Reusable Software既是基于此原则而开发的。其他的原则也是对它的实现提供了路径。
2) Liskov Substituition Principle(LSP),里氏代换原则,很严格的原则,规则是“子类必须能够替换基类,否则不应当设计为其子类。”也就是说,子类只能去扩展基类,而不是隐藏或覆盖基类。
3) Dependence Inversion Principle(DIP),依赖倒换原则,“设计要依赖于抽象而不是具体化”。换句话说就是设计的时候我们要用抽象来思考,而不是一上来就开始划分我需要哪些哪些类,因为这些是具体。这样做有什么好处呢?人的思维本身实际上就是很抽象的,我们分析问题的时候不是一下子就考虑到细节,而是很抽象的将整个问题都构思出来,所以面向抽象设计是符合人的思维的。另外这个原则会很好的支持OCP,面向抽象的设计使我们能够不必太多依赖于实现,这样扩展就成为了可能,这个原则也是另一篇文章《Design by Contract》的基石。
4) Interface Segregation Principle(ISP),接口隔离原则,“将大的接口打散成多个小接口”,这样做的好处很明显,我不知道有没有必要再继续描述了,为了节省篇幅,实际上我对这些原则只是做了一个小总结,如果有需要更深入了解的话推荐看《Java与模式》,MS MVP的一:本巨作!^_^
5) 单一职责:一个类的功能尽量单一,降低耦合
6) Law of Demeter or Least Knowlegde Principle(LoD or LKP),迪米特法则或最少知识原则,这个原则首次在Demeter系统中得到正式运用,所以定义为迪米特法则。它讲的是“一个对象应当尽可能少的去了解其他对象”。也就是又一个关于如何松耦合(Loosely-Coupled)的法则。
好了,以上是6大原则(或法则)的介绍,对这些原则的深入研究正是如何得到设计模式的道路。在进行了深入了解后我们就可以开始看看设计模式了,设计模式正是对这些法则的应用,著名的设计模式有四人帮(Gang of Four,GoF)的23个模式,除此之外还有很多其他的一些著名模式,大家可以慢慢研究,如果能自己产出一两个模式的话那就太好了,证明你也是高手了!^_^
魔术函数
1.__construct()
PHP 构造方法 __construct() 允许在实例化一个类之前先执行构造方法。
构造方法
构造方法是类中的一个特殊方法。当使用 new 操作符创建一个类的实例时,构造方法将会自动调用,其名称必须是 __construct() 。
在一个类中只能声明一个构造方法,而是只有在每次创建对象的时候都会去调用一次构造方法,不能主动的调用这个方法,所以通常用它执行一些有用的初始化任务。该方法无返回值。
语法:
function __construct(arg1,arg2,...){ ......}
例子:
<?phpclass Person { var $name; var $age; //定义一个构造方法初始化赋值 function __construct($name, $sex, $age) { $this->name=$name; $this->age=$age; } function say() { echo "我的名字叫:".$this->name."<br />";echo "我的年龄是:".$this->age; }}$p1=new Person("张三", 20);$p1->say();?>
运行该例子,输出:
我的名字叫:张三的年龄是:20
在该例子中,通过构造方法对对象属性进行初始化赋值。
提示
PHP 不会在本类的构造方法中再自动的调用父类的构造方法。要执行父类的构造方法,需要在子类的构造方法中调用 parent::__construct() 。
2。__destruct()
当删除一个对象或对象操作终止时被调用。
PHP 析构方法 __destruct() 允许在销毁一个类之前执行执行析构方法。
析构方法
与构造方法对应的就是析构方法,析构方法允许在销毁一个类之前执行的一些操作或完成一些功能,比如说关闭文件、释放结果集等。析构函数不能带有任何参数,其名称必须是 __destruct() 。
语法:
function __destruct(){ ......}
我们在上面的例子中加入下面的析构方法:
//定义一个析构方法function __destruct(){ echo "再见".$this->name;}
再次运行该例子,输出:
我的名字叫:张三的年龄是:20再见张三
提示
- 和构造方法一样,PHP 不会在本类中自动的调用父类的析构方法。要执行父类的析构方法,必须在子类的析构方法体中手动调用 parent::__destruct() 。
- 试图在析构函数中抛出一个异常会导致致命错误。
- 在 PHP4 版本中,构造方法的名称必须与类名相同,且没有析构方法。
3。__call()
对象调用某个方法,
若方法存在,则直接调用;
若不存在,则会去调用__call函数。
__call() 方法用于监视错误的方法调用。
__call()(Method overloading)
为了避免当调用的方法不存在时产生错误,可以使用 __call() 方法来避免。该方法在调用的方法不存在时会自动调用,程序仍会继续执行下去。
语法:
function __call(string $function_name, array $arguments){ ......}
该方法有两个参数,第一个参数 $function_name 会自动接收不存在的方法名,第二个 $args 则以数组的方式接收不存在方法的多个参数。
在类里面加入:
function __call($function_name, $args){ echo "你所调用的函数:$function_name(参数:<br />"; var_dump($args); echo ")不存在!";}
当调用一个不存在的方法时(如 test() 方法):
$p1=new Person();$p1->test(2,"test");
输出的结果如下:
你所调用的函数:test(参数:array(2) { [0]=>int(2) [1]=>string(4) "test"})不存在!
4。__get()
读取一个对象的属性时,
若属性存在,则直接返回属性值;
若不存在,则会调用__get函数
- __set() 方法用于设置私有属性值。
实际应用中,经常会把类的属性设置为私有(private),那么需要对属性进行访问时,就会变得麻烦。虽然可以将对属性的访问写成一个方法来实现,但 PHP 提供了一些特殊方法来方便此类操作。
__set()
__set() 方法用于设置私有属性值:
function __set($property_name, $value){ $this->$property_name = $value; }
在类里面使用了 __set() 方法后,当使用 $p1->name = "张三"; 这样的方式去设置对象私有属性的值时,就会自动调用 __set() 方法来设置私有属性的值。
5。__set()
设置一个对象的属性时,
若属性存在,则直接赋值;
若不存在,则会调用__set函数。
- __get() 方法用于获取私有属性值。
__get()
__get() 方法用于获取私有属性值:
function __set($property_name, $value){ return isset($this->$property_name) ? $this->$property_name : null;}
例子:
<?phpclass Person { private $name; private $sex; private $age; //__set()方法用来设置私有属性 function __set($property_name, $value) { echo "在直接设置私有属性值的时候,自动调用了这个 __set() 方法为私有属性赋值<br />"; $this->$property_name = $value; } //__get()方法用来获取私有属性 function __get($property_name) { echo "在直接获取私有属性值的时候,自动调用了这个 __get() 方法<br />"; return isset($this->$property_name) ? $this->$property_name : null; }}$p1=new Person();//直接为私有属性赋值的操作, 会自动调用 __set() 方法进行赋值$p1->name = "张三";//直接获取私有属性的值, 会自动调用 __get() 方法,返回成员属性的值echo "我的名字叫:".$p1->name;?>
运行该例子,输出:
在直接设置私有属性值的时候,自动调用了这个 __set() 方法为私有属性赋值在直接获取私有属性值的时候,自动调用了这个 __get() 方法我的名字叫:张三
6。__toString()
打印一个对象的时被调用。如echo $obj;或print $obj;
7。__clone()
克隆对象时被调用。如:$t=new Test();$t1=clone $t;
clone 关键字用于克隆一个完全一样的对象,__clone() 方法来重写原本的属性和方法。
对象克隆
有的时候我们需要在一个项目里面使用两个或多个一样的对象,如果使用 new 关键字重新创建对象,再赋值上相同的属性,这样做比较烦琐而且也容易出错。PHP 提供了对象克隆功能,可以根据一个对象完全克隆出一个一模一样的对象,而且克隆以后,两个对象互不干扰。
使用关键字 clone 来克隆对象。语法:
$object2 = clone $object;
例子:
<?phpclass Person { private $name; private $age; function __construct($name, $age) { $this->name=$name; $this->age=$age; } function say() { echo "我的名字叫:".$this->name."<br />";echo "我的年龄是:".$this->age; }}$p1 = new Person("张三", 20);$p2 = clone $p1;$p2->say();?>
运行例子,输出:
我的名字叫:张三我的年龄是:20
__clone()
如果想在克隆后改变原对象的内容,需要在类中添加一个特殊的 __clone() 方法来重写原本的属性和方法。__clone() 方法只会在对象被克隆的时候自动调用。
例子:
<?phpclass Person { private $name; private $age; function __construct($name, $age) { $this->name = $name; $this->age = $age; } function say() { echo "我的名字叫:".$this->name;echo " 我的年龄是:".$this->age."<br />"; } function __clone() { $this->name = "我是假的".$this->name; $this->age = 30; }}$p1 = new Person("张三", 20);$p1->say();$p2 = clone $p1;$p2->say();?>
运行例子,输出:
我的名字叫:张三 我的年龄是:20我的名字叫:我是假的张三 我的年龄是:30
8。__sleep()
serialize之前被调用。若对象比较大,想删减一点东东再序列化,可考虑一下此函数。
9。__wakeup()
unserialize时被调用,做些对象的初始化工作。
10。__isset()
检测一个对象的属性是否存在时被调用。如:isset($c->name)。
__isset()
__isset() 方法用于检测私有属性值是否被设定。
如果对象里面成员是公有的,可以直接使用 isset() 函数。如果是私有的成员属性,那就需要在类里面加上一个 __isset() 方法:
private function __isset($property_name){ return isset($this->$property_name);}
这样当在类外部使用 isset() 函数来测定对象里面的私有成员是否被设定时,就会自动调用 __isset() 方法来检测。
11。__unset()
unset一个对象的属性时被调用。如:unset($c->name)。
__unset()
__unset() 方法用于删除私有属性。
同 isset() 函数一样,unset() 函数只能删除对象的公有成员属性,当要删除对象内部的私有成员属性时,需要使用__unset() 方法:
private function __unset($property_name){ unset($this->$property_name);}
12。__set_state()
调用var_export时,被调用。用__set_state的返回值做为var_export的返回值。
13。__autoload()
实例化一个对象时,如果对应的类不存在,则该方法被调用。
__autoload() 方法用于自动加载类。
__autoload()
在实际项目中,不可能把所有的类都写在一个 PHP 文件中,当在一个 PHP 文件中需要调用另一个文件中声明的类时,就需要通过 include 把这个文件引入。不过有的时候,在文件众多的项目中,要一一将所需类的文件都 include 进来,一个很大的烦恼是不得不在每个类文件开头写一个长长的包含文件的列表。我们能不能在用到什么类的时候,再把这个类所在的 php 文件导入呢?
为此,PHP 提供了 __autoload() 方法,它会在试图使用尚未被定义的类时自动调用。通过调用此函数,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类。
__autoload() 方法接收的一个参数,就是欲加载的类的类名,所以这时候需要类名与文件名对应,如 Person.php ,对应的类名就是 Pserson 。
例子:
Pserson.php
<?php<?phpclass Person { private $name; private $age; function __construct($name, $age) { $this->name = $name; $this->age = $age; } function say() {echo "我的名字叫:".$this->name."<br />";echo " 我的年龄是:".$this->age; }}?>
test.php
<?phpfunction __autoload($class_name) { require_once $class_name.'.php';}//当前页面 Pserson 类不存在则自动调用 __autoload() 方法,传入参数 Person$p1 = new Person("张三","20");$p1 -> say();?>
运行 test.php ,输出:
我的名字叫:张三我的年龄是:20
魔术常量
1。__LINE__
返回文件中的当前行号。
2。__FILE__
返回文件的完整路径和文件名。如果用在包含文件中,则返回包含文件名。自 PHP 4.0.2 起,__FILE__ 总是包含一个绝对路径,而在此之前的版本有时会包含一个相对路径。
3。__FUNCTION__
返回函数名称(PHP 4.3.0 新加)。自 PHP 5 起本常量返回该函数被定义时的名字(区分大小写)。在 PHP 4 中该值总是小写字母的。
4。__CLASS__
返回类的名称(PHP 4.3.0 新加)。自 PHP 5 起本常量返回该类被定义时的名字(区分大小写)。在 PHP 4 中该值总是小写字母的。
5。__METHOD__
返回类的方法名(PHP 5.0.0 新加)。返回该方法被定义时的名字(区分大小写)。
(1)初识魔术方法
Php5.0发布以来为我们提供了很多面向对象的特性,尤其是为我们提供了好多易用的魔术方法,这些魔术方法可以让我们简化我们的编码,更好的设计我们的系统。今天我们就来认识下php5.0给我们提供的魔术方法。
- 面向对象的设计模式及魔术函数
- PHP面向对象 1.7 常见的魔术方法及应用
- 面向对象设计原则及设计模式
- php面向对象中的魔术函数
- 面向对象的六大原则及设计模式概览
- 面向对象的设计模式
- 面向对象的设计模式
- 面向对象的设计模式
- Android设计模式及面向对象原则
- PHP之面向对象的魔术方法
- 面向对象--魔术方法
- 面向对象设计模式
- 面向对象设计模式
- 面向对象设计模式
- 面向对象--设计模式
- 【设计模式】面向对象
- 设计模式/面向对象
- 面向对象-设计模式
- 自定义控件ViewPagerIndicator的使用
- [翻译]WebRender:让网页渲染如丝顺滑
- Altium Designer 13.0 画图技巧
- 计算圆和长方形的面积
- js严格模式
- 面向对象的设计模式及魔术函数
- C# 系统应用之通过注册表获取USB使用记录
- ImageLoader缓存一个网址图片并存到SD卡上
- rabbitMq与spring的整合
- 内存分配策略
- QoS基础及技术原理——2
- 欢迎使用CSDN-markdown编辑器
- XListView上拉加载下拉刷新
- python发送各类邮件