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

开发 后端 前端
在学习PHP的时候,感觉自己对面向对象理解还不深刻,很多时候是一头雾水。通过别人的推荐,找到了这篇通过星际争霸来讲解面向对象概念的文章,转载出来供有需要的朋友学习。

​在学习PHP的时候,感觉自己对面向对象理解还不深刻,很多时候是一头雾水。通过别人的推荐,找到了这篇通过星际争霸来讲解面向对象概念的文章,转载出来供有需要的朋友学习。

一、类和对象

如果玩家制造了一个机枪兵,那么我们怎么表示他呢,因为每个机枪兵有几个基本的数据要记录:剩余的血,杀敌数量,攻击力等等。我们可以用一个数组来记录一个机枪兵剩余的血和杀敌数量,因为这对于每个机枪兵是独立的。但攻击力比较麻烦,因为经过升级,攻击力会增加,这就必须要找出所有表示机枪兵的数组,然后进行修改,非常麻烦。从这里我们可以看出一件事情,首先每个机枪兵有独立的数据需要记录和修改,比如剩余的血。同时他们有相同的数据需要共用,比如攻击力。这时候面向对象就能帮上我们的忙了。

1.1、类的定义

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

  1. class marine 
  2.    public $blood = 50; //剩余的血 
  3.    public $kills = 0; //杀敌数量 
  4.    //这个函数(通常叫做方法)表示攻击敌人时候的运行代码    function attack($enemy) 
  5.    { 
  6.    //攻击敌人的代码 
  7.    } 

这叫做类,我们建立了一个表示所有机枪兵的类marine,这里面保留了需要每个兵独有的数据,比如上面代码里的剩余的血。

1.2、对象的创建和使用

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

  1. $m1 = new marine(); 

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

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

我们再建立一个机枪兵

  1. $m2 = new marine(); 

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

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

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

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

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

二、构造函数和析构函数

每次我们新建一个机枪兵的时候,总人口应该加1,如果一个机枪兵被杀,人口应该减少1。可以通过构造函数和析构函数来自动处理:

  1. class marine 
  2.    //构造函数 
  3.    function __construct() 
  4.    { 
  5.    //增加总人口的代码 
  6.    } 
  7.    //析构函数 
  8.    function __destruct() 
  9.    { 
  10.    //减少总人口的代码 
  11.    } 

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

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

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

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

三、静态

机枪兵的攻击力是属于所有机枪兵对象,每个机枪兵的攻击力都是一样的,如果升级,应该一起变化。这就用到static,表示静态:

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

静态属性表示类所有的对象都共享的属性,一旦改变,所有的对象都跟着变化。静态属性用static开头,比如上面的static $attackNumber。静态属性可以用类直接访问:

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

如果类以内的函数访问,用self::$attackNumber表示本类的$attackNumber属性。所以如果我们升级了机枪兵的攻击力,所有的 机枪兵都受影响,这就是面向对象的好处之一,也解决了我们前面讨论的共同数据的问题。函数也可以是静态的,这样就可以用类直接访问,不需要新建对象来调 用:

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

#p#

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

marine::upgrade();
  1. //建筑类 
  2. class building 
  3.    function fly() 
  4.    { 
  5.    //建筑飞行的代码 
  6.    } 
  7. //兵营类 
  8. class marineBuilding extends building 
  9.    function createMarine() 
  10.    { 
  11.    //制造机枪兵的代码 
  12.    } 
  13. //坦克房类 
  14. class tankBuilding extends building 
  15.    function createTank() 
  16.    { 
  17.    //制造坦克的代码 
  18.    } 
  19.  
  20. 接下来,我们看看继承产生的效果: 
  21. //如果造了一个兵营: 
  22. $mb1 = new marineBuilding(); 
  23. /** 
  24. 一旦他需要飞行,就可以直接使用建筑类的函数fly(),尽管兵营类的定义里没有这个函数 
  25. */ 
  26. $mb1->fly(); 
  27. //而他要制造机枪兵的时候: 
  28. $mb1->createMarine(); 

同样是继承建筑类的坦克房类,就无法制造机枪兵,因为这是兵营类的个性。如果在子类中的函数调用父类的函数,要使用parent,比如parent::fly()。注意,一个类只能有一个父类,PHP不允许多重继承,也就是说一个孩子只能有一个爹,一个爹可以有N个孩子!

五、访问控制

如果用$attackNumber = 10表示属性的话,系统默认是public $attackNumber = 10,所以建议这样写:

  1. class marine 
  2. public static $attackNumber = 10; //攻击力的数字 

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

  1. //补丁 
  2. marine::$attackNumber = 10000; 

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

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

这样一来,只有升级才能改变机枪兵的攻击力。但是现在往往是团队开发,而且很多用到类的继承,如果private的话,子类就无法访问了,但又不希望随便都可以修改某些属性。那么可以用protected,protected的属性可以被子类的函数访问。

六、重载

6.1、属性重载

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

  1. //地面部队 
  2. class groundArmy 
  3. public $attackNumber = 5; 
  4. //机枪兵 
  5. class marine extends groundArmy 
  6. public $attackNumber = 10; //攻击力的数字 
  7. $m1 = new marine();//新建一个机枪兵 
  8. echo $m1->attackNumber;//显示攻击力为10 

6.2、函数重载

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

#p#

  1. //隐形能力类 
  2. class concealAbility 
  3.    //这个函数表示隐形的运行代码    function conceal() 
  4.    { 
  5.       //隐形的运行代码 
  6.    } 
  7. //鬼兵类 
  8. class ghost extends concealAbility 
  9. $energy = 150; 
  10.    //这个函数表示隐形的运行代码    function conceal() 
  11.    { 
  12.       //隐形的运行代码 
  13.       //减少鬼兵的能量,$this表示当前对象,也就是当前这个鬼兵 
  14.       $this->energy -= 25; 
  15.    } 
  16. //黑暗圣堂类 
  17. class DarkTemplar extends concealAbility 
  18.    //这个函数表示隐形的运行代码    function conceal() 
  19.    { 
  20.       //隐形的运行代码,不影响能量 
  21.    } 
  22. //新建一个鬼兵 
  23. $g1 = new ghost(); 
  24. //显示能量为150 
  25. echo $g1->energy; 
  26. //鬼兵隐形 
  27. $g1->conceal(); 
  28. //显示能量为125 
  29. echo $g1->energy; 
  30. //新建一个黑暗圣堂 
  31. $d1 = new DarkTemplar(); 
  32. //黑暗圣堂隐形,他没有能量属性 
  33. $g1->conceal(); 

七、接口

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

  1. //隐形能力的接口 
  2. interface concealAbility 
  3. public function conceal(); 
  4. //飞行能力的接口 
  5. interface flyAbility 
  6. public function fly(); 
  7. //侦察机类 
  8. class Wraith implements flyAbility, concealAbility 
  9.    //这个函数表示侦察机飞行的运行代码    function fly() 
  10.    { 
  11.       //飞行的运行代码 
  12.    } 
  13.    //这个函数表示侦察机隐形的运行代码    function conceal() 
  14.    { 
  15.       //隐形的运行代码 
  16.    } 

八、总结

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

原文链接:http://www.biaodianfu.com/starcraft-object-oriented.html

责任编辑:陈四芳 来源: biaodianfu.com
相关推荐

2012-01-17 12:39:09

JavaSwing

2010-01-14 17:17:32

云计算

2010-07-19 13:15:49

星际争霸2

2014-03-18 15:23:58

星际争霸ARM平台

2019-01-25 18:37:20

AI数据科技

2011-05-13 11:49:42

网络安全技术周刊

2009-11-23 19:24:01

PHP面向对象编程

2010-01-18 16:57:09

云计算星际争霸

2021-12-01 10:01:52

AI 游戏人工智能

2023-11-18 09:48:23

2009-08-18 09:47:44

百强游戏任天堂

2022-06-02 15:19:31

架构智能强化学习

2019-08-12 08:43:53

GitHub代码开发者

2010-08-01 22:30:12

2010-08-03 09:43:59

IT技术周刊

2009-10-13 14:19:03

VB.NET面向对象编

2009-07-24 08:17:37

巫妖王之怒亮相Chin魔兽世界

2011-04-19 18:17:36

2010-06-18 11:28:14

2019-01-30 11:17:46

点赞
收藏

51CTO技术栈公众号