用星际争霸讲解面向对象的概念

        在学习PHP的时候,感受本身对面向对象理解还不深入,不少时候是一头雾水。经过别人的推荐,找到了这篇经过星际争霸来说解面向对象概念的文章,转载出来供有须要的朋友学习。

   1、类和对象 php

   若是玩家制造了一个机枪兵,那么咱们怎么表示他呢,由于每一个机枪兵有几个基本的数据要记录:剩余的血,杀敌数量,攻击力等等。咱们能够用一个数组来记录一个机枪兵剩余的血和杀敌数量,由于这对于每一个机枪兵是独立的。但攻击力比较麻烦,由于通过升级,攻击力会增长,这就必需要找出全部表示机枪兵的数组,而后进行修改,很是麻烦。从这里咱们能够看出一件事情,首先每一个机枪兵有独立的数据须要记录和修改,好比剩余的血。同时他们有相同的数据须要共用,好比攻击力。这时候面向对象就能帮上咱们的忙了。 设计模式

   1.一、类的定义 数组

   咱们先来处理一部分问题,也就是每一个机枪兵独有的数据。 框架

class marine
{
   public $blood = 50; //剩余的血
   public $kills = 0; //杀敌数量
   //这个函数(一般叫作方法)表示攻击敌人时候的运行代码    function attack($enemy)
   {
   //攻击敌人的代码
   }
}

   这叫作类,咱们创建了一个表示全部机枪兵的类marine,这里面保留了须要每一个兵独有的数据,好比上面代码里的剩余的血。 函数

   1.二、对象的建立和使用 学习

   接下来咱们来使用对象,也就是每一个机枪兵: ui

$m1 = new marine();

   经过new后面加一个类的名字和括号,咱们新建了一个机枪兵$m1,$m1被叫作类marine的对象,咱们能够把它想象成一个特殊变量,只不过里面保存了多个数据。若是须要使用或者操做某个机枪兵的血(对象的属性),只要用$m1->blood来表示就能够了: this

echo $m1->blood;//输出机枪兵$m1剩余的血

   咱们再创建一个机枪兵 spa

$m2 = new marine();

   若是此时$m1被敌人攻击过了,还剩下10个血。而$m2没受过攻击: 设计

echo $m1->blood;//结果是10
echo $m2->blood;//结果是50

   使用对象能够很简单的保存每一个机枪兵的血,不会互相影响。若是机枪兵$m1攻击敌人的时候,能够这样使用对象的方法:

$m1->attack($z1);//假设攻击的是某个小狗的对象$z1

   不一样的类内能够用同名的函数,好比小狗的类Zergling里面也能够有一个函数attack。要注意的是,从PHP5开始,不管在哪里改变一个对象的属性,都能改变它。好比上面一个小狗对象被做为参数传入机枪兵的attack函数,执行函数以后这个小狗对象的血减小了,这和通常的函数不一样。但这是很直观的,若是一个小狗被攻击了,它的血就应该减小。

   2、构造函数和析构函数

   每次咱们新建一个机枪兵的时候,总人口应该加1,若是一个机枪兵被杀,人口应该减小1。能够经过构造函数和析构函数来自动处理:

class marine
{
   //构造函数
   function __construct()
   {
   //增长总人口的代码
   }
   //析构函数
   function __destruct()
   {
   //减小总人口的代码
   }
}

   在一个类中,名字为__construct的函数叫作构造函数,每次new新建一个类的对象的时候就会执行:

$m1 = new marine();//每次制造一个机枪兵时系统会调用类marine的构造函数,自动增长总人口

   在一个类中,名字为__destruct的函数叫作析构函数,每次销毁一个类的对象的时候就会执行:

unset($m1);//unset能够用于对象,表示销毁一个对象。每次一个机枪兵被杀时系统会调用类marine的析构函数,自动减小总人口

   3、静态

   机枪兵的攻击力是属于全部机枪兵对象,每一个机枪兵的攻击力都是同样的,若是升级,应该一块儿变化。这就用到static,表示静态:

class marine
{
   static $attackNumber = 10; //攻击力的数字
   //这个函数表示攻击敌人时候的运行代码    function attack($enemy)
   {
   //攻击敌人的代码,$enemy->blood表示敌人对象的血属性
   $enemy->blood -= self::$attackNumber;
   }
}

   静态属性表示类全部的对象都共享的属性,一旦改变,全部的对象都跟着变化。静态属性用static开头,好比上面的static $attackNumber。静态属性能够用类直接访问:

echo marine::$attackNumber;//显示10

   若是类之内的函数访问,用self::$attackNumber表示本类的$attackNumber属性。因此若是咱们升级了机枪兵的攻击力,全部的机枪兵都受影响,这就是面向对象的好处之一,也解决了咱们前面讨论的共同数据的问题。函数也能够是静态的,这样就能够用类直接访问,不须要新建对象来调用:

class marine
{
   static $attackNumber = 10; //攻击力的数字
   //这个函数表示机枪兵升级的运行代码    static  function upgrade()
   {
   self::$attacknum++;
   }
}

   若是科技建筑升级完毕,直接就调用这个函数:

marine::upgrade();

   4、继承

   兵营用来造机枪兵,坦克房用来制造坦克,他们都是建筑,可是却有不少不一样,若是用一个类“建筑”来表示,很困难。但咱们要保留他们的共性,好比都能飞行,不但愿飞行的代码在各个类重复写,又要让他们能各自独立的生产不一样的东西。因此咱们能够用继承来处理,继承表示父子关系,被继承的叫父类,继承的叫子类。用extends表示继承

//建筑类
class building
{
   function fly()
   {
   //建筑飞行的代码
   }
}
//兵营类
class marineBuilding extends building
{
   function createMarine()
   {
   //制造机枪兵的代码
   }
}
//坦克房类
class tankBuilding extends building
{
   function createTank()
   {
   //制造坦克的代码
   }
}

   接下来,咱们看看继承产生的效果:

//若是造了一个兵营:
$mb1 = new marineBuilding();
/**
一旦他须要飞行,就能够直接使用建筑类的函数fly(),尽管兵营类的定义里没有这个函数
*/
$mb1->fly();
//而他要制造机枪兵的时候:
$mb1->createMarine();

   一样是继承建筑类的坦克房类,就没法制造机枪兵,由于这是兵营类的个性。若是在子类中的函数调用父类的函数,要使用parent,好比parent::fly()。注意,一个类只能有一个父类,PHP不容许多重继承,也就是说一个孩子只能有一个爹,一个爹能够有N个孩子!

   5、访问控制

   若是用$attackNumber = 10表示属性的话,系统默认是public $attackNumber = 10,因此建议这样写:

class marine
{
public static $attackNumber = 10; //攻击力的数字
}

   public表示这个属性是公共的,也就是在任何地方均可以访问和操做的。但这就存在一些问题,若是有玩家知道了类marine的一些代码结构,那他作个简单的补丁程序,运行的时候加载上去:

//补丁
marine::$attackNumber = 10000;

   这样的话,他的机枪兵有10000的攻击力,呵呵,这样的话,谁打得过他!为此咱们要用private,表示这个属性只有类里面的函数才能访问:

class marine
{
    private static $attackNumber = 10; //攻击力的数字
   //这个函数表示机枪兵升级的运行代码    function upgrade()
   {
      //这样防止无限升级
      if(self::$attacknum<13)
      {
      self::$attacknum++;
      }
   }
}

   这样一来,只有升级才能改变机枪兵的攻击力。可是如今每每是团队开发,并且不少用到类的继承,若是private的话,子类就没法访问了,但又不但愿随便均可以修改某些属性。那么能够用protected,protected的属性能够被子类的函数访问。

   6、重载

   6.一、属性重载

   若是咱们把地面部队做为一个类,让机枪兵类来继承他,这时候若是地面部队类和机枪兵类里面都定义了攻击力$attackNumber,那么每一个兵的攻击力就决定于机枪兵类,而不是地面部队。这就叫作重载。

//地面部队
class groundArmy
{
public $attackNumber = 5;
}
//机枪兵
class marine extends groundArmy
{
public $attackNumber = 10; //攻击力的数字
}
$m1 = new marine();//新建一个机枪兵
echo $m1->attackNumber;//显示攻击力为10

   6.二、函数重载

   重载也能够用于函数,子类的函数若是和父类函数同名,除非另行说明,不然子类的对象默认调用子类内的函数。好比人族的鬼兵类ghost和神族类的黑暗圣堂类(隐刀),都是隐形兵种,可是鬼兵隐形的时候会减小能量,黑暗圣堂根本没有能量属性。若是咱们把隐形能力做为父类,鬼兵类ghost和神族类的黑暗圣堂类DarkTemplar来继承它,同时实现不一样的隐形代码:

//隐形能力类
class concealAbility
{
   //这个函数表示隐形的运行代码    function conceal()
   {
      //隐形的运行代码
   }
}
//鬼兵类
class ghost extends concealAbility
{
$energy = 150;
   //这个函数表示隐形的运行代码    function conceal()
   {
      //隐形的运行代码
      //减小鬼兵的能量,$this表示当前对象,也就是当前这个鬼兵
      $this->energy -= 25;
   }
}
//黑暗圣堂类
class DarkTemplar extends concealAbility
{
   //这个函数表示隐形的运行代码    function conceal()
   {
      //隐形的运行代码,不影响能量
   }
}
//新建一个鬼兵
$g1 = new ghost();
//显示能量为150
echo $g1->energy;
//鬼兵隐形
$g1->conceal();
//显示能量为125
echo $g1->energy;
//新建一个黑暗圣堂
$d1 = new DarkTemplar();
//黑暗圣堂隐形,他没有能量属性
$g1->conceal();

   7、接口

   PHP不容许多重继承,那么有些问题就难办了。假如为了规范处理,咱们把隐形的能力创建一个类,而后把飞行能力放一个类,那么人族的侦察机怎么处理?不能继承两个类!那咱们不用继承也行,可是开发组的其余人一旦涉及到侦察机,要把长长的代码读一遍吗?有没有可能知道类的全部方法的简要描述?能够用到接口interface,一个类能够执行(继承)多个接口,接口中定义的函数不能有函数体,执行接口的类必须将这些函数完整定义。这样咱们知道侦察机实现了飞行能力接口,必然有接口里面描述的飞行方法:

//隐形能力的接口
interface concealAbility
{
public function conceal();
}
//飞行能力的接口
interface flyAbility
{
public function fly();
}
//侦察机类
class Wraith implements flyAbility, concealAbility
{
   //这个函数表示侦察机飞行的运行代码    function fly()
   {
      //飞行的运行代码
   }
   //这个函数表示侦察机隐形的运行代码    function conceal()
   {
      //隐形的运行代码
   }
}

   8、总结

   咱们讨论了PHP面向对象的基本知识,经过星际争霸这一经典的游戏来讲明,你们能够看到面向对象的初步做用。咱们看到经过面向对象可使代码更加清晰,类将代码组织起来,比较方便的重复使用。同时对象也减小了变量的冲突,方便相关性数据的保存和使用。若是要解决的问题涉及不少方面,面向对象能够演化出更加灵活和有技巧的方式,好比一般提到的设计模式,和不少框架。固然,面向对象也有缺点,从上面的代码能够看到,首先代码就多了,简单的任务若是定义许多类,反而麻烦。对于简单任务,面向对象也可能使代码运行的效率下降

相关文章
相关标签/搜索