Q:面对对象和面向过程的优缺点,结合实例进行阐述

A

一、个人理解,面向对象相对于面向过程较显著的优势莫过于可扩展性、可维护性。众所周知在软件开发过程中,开发人员与客户需要不断的沟通,而客户的需求也往往在不断的变化,软件的功能也不是一成不变的。如果采用面向过程的方法来进行软件开发,当用户需求发生变化时,比如要求修改现有软件功能的实现方式或者要求追加新的功能时,就需要自顶向下地修改模块的结构,有时候甚至整个软件系统的设计被完全推翻。

相比之下,面向对象所提供的可扩展性保证了当软件必须增加新的功能时,能够在现有系统结构的基础上,方便的创建新的子系统,而不需要改变软件系统现有的结构,也不会影响已经存在的子系统。可维护性则保证了当用户需求发生变化时,只需要修改局部的子系统的少量程序代码,而不会牵一发动全身。

    举一个例子,暴雪公司开发的魔兽争霸游戏,这个游戏里面有很多人物角色,例如我们要编程实现美杜莎这个角色的技能攻击动作。如果使用面向过程的方法来实现。本例使用C++Visual C++ 6.0环境下调试。

#include<iostream>

using namespace std;

 

#define SPLIT_SHOT 1

#define MYSTIC_SNAKE 2

#define MANA_SHIELD 3

 

void useSplitShot()                //使用分裂箭技能

{

    cout<<"Split Shot"<<endl;

}

void useMysticSnake()              //使用秘术异蛇技能

{

    cout<<"Mystic Snake"<<endl;

}

void useManaShield()            //使用魔法护盾技能

{

    cout<<"Mana Shield"<<endl;

}

 

void useSkill()                    //使用技能

{

    int skill;

    cin>>skill;                     //输入技能快捷键

    switch(skill)

    {

       case SPLIT_SHOT:

           useSplitShot();

           break;

       case MYSTIC_SNAKE:

           useMysticSnake();

           break;

       case MANA_SHIELD:

           useManaShield();

           break;

       default:

           cout<<"无法使用技能"<<endl;

           break;

    }

}

 

int main()

{

    useSkill();

    return 0;

}

    假如有一天玩家向暴雪反映,美杜莎这个英雄的技能太少啦,我们希望再增加一个技能。这个时候假如暴雪决定增加一个石化凝视(Stone Gaze)技能,那么需要进行以下三步:

    (1) 在整个系统范围内,增加一个常量:

       #define STONE_GAZE 4

    (2) 在整个系统范围内增加一个新的石化凝视技能模块:

       void useStoneGaze()                 //使用石化凝视技能

       {

           cout<<"Stone Gaze"<<endl;

       }

    (3) 在使用技能模块useSkill()内增加以下逻辑:

       case STONE_GAZE:

           useStoneGaze();

           break;

    由此可见,面向过程的开发方法制约了软件的可维护和可扩展性,模块之间的松耦合性不高,修改或增加一个模块会影响到其他的模块。

    如果采用面向对象的方式,则该功能可以这样实现。本例使用JavaMyEclipse环境下调试。

Skill.java

public interface Skill      //技能接口

{

    void useSkill();         //使用技能

}

 

SplitShot.java

public class SplitShot implements Skill           //分裂箭技能类

{

    public void useSkill()

    {

       System.out.println("Split Shot");          //使用分裂箭技能

    }

}

 

MysticSnake.java

public class MysticSnake implements Skill         //秘术异蛇技能类

{

    public void useSkill()

    {

       System.out.println("Mystic Snake");       //使用秘术异蛇技能

    }

}

 

ManaShield.java

public class ManaShield implements Skill          //魔法护盾技能类

{

    public void useSkill()

    {

       System.out.println("Mana Shield");         //使用魔法护盾技能

    }

}

 

SkillFactory.java

import java.util.HashMap;

import java.util.Map;

public class SkillFactory              //技能工厂类

{

    public static final int SPLIT_SHOT = 1;

    public static final int MYSTIC_SNAKE = 2;

    public static final int MANA_SHIELD = 3;

   

    private static Map<Integer, String> skills = new HashMap<Integer, String>();

    static

    {

       skills.put(new Integer(SPLIT_SHOT), "SplitShot");

       skills.put(new Integer(MYSTIC_SNAKE), "MysticSnake");

       skills.put(new Integer(MANA_SHIELD), "ManaShield");

    }

    public static Skill getSkill(int key)

    {

       try

       {

           String className = skills.get(new Integer(key));

           return (Skill)Class.forName(className).newInstance();

       }

       catch(Exception e)

       {

           e.printStackTrace();

           return null;

       }

    }

}

 

Medusa.java

import java.io.BufferedReader;

import java.io.InputStreamReader;

public class Medusa          //角色类——美杜莎

{

    public void useSkill() throws Exception   //实现美杜莎释放技能的方法

    {

       BufferedReader input = new BufferedReader(new InputStreamReader(System.in));

       int key = Integer.parseInt(input.readLine());   //输入技能快捷键

       Skill skill = SkillFactory.getSkill(key);

       if(skill==null)

       {

           System.out.println("无法使用技能");

       }

       else

       {

           skill.useSkill();

       }

    }

   

    public static void main(String[] args) throws Exception

    {

       new Medusa().useSkill();    //美杜莎释放技能

    }

}

    假设同样的情况,暴雪公司需要给美杜莎增加一个新的技能——石化凝视(Stone Gaze),那么只需要对该系统做如下修改:

    (1) 增加一个石化凝视技能类StoneGaze

       

public class StoneGaze implements Skill   //石化凝视技能类

{

           public void useSkill()

           {

              System.out.println("Stone Gaze");      //使用石化凝视技能

           }

}

    (2) SkillFactory类中增加一个STONE_GAZE常量,并修改静态代码块。修改过的代码如下:

public static final int SPLIT_SHOT = 1;

              public static final int MYSTIC_SNAKE = 2;

              public static final int MANA_SHIELD = 3;

        public static final int STONE_GAZE = 4;

   

private static Map<Integer, String> skills = new HashMap<Integer, String>();

              static

              {

                     skills.put(new Integer(SPLIT_SHOT), "SplitShot");

                     skills.put(new Integer(MYSTIC_SNAKE), "MysticSnake");

                     skills.put(new Integer(MANA_SHIELD), "ManaShield");

           skills.put(new Integer(STONE_GAZE), "StoneGaze");

        }

    由此可见,当Medusa系统增加技能时,仅仅修改了Skill子系统,对Medusa子系统并没有任何影响。此外,Skill子系统具有良好的可扩展性,当Skill子系统需要增加新的技能时,无须修改Skill子系统的系统结构,只需要创建新的技能实现类即可。上面的例子比较简单,所以面向对象的易扩展易维护的优势体现的不太明显,但是如果随着客户提出的问题域复杂度的增加,修改面向过程软件的难度会以几何倍数增长,甚至会导致整个系统不得不推翻重做。

二、除了可扩展性和可维护性外,面向对象还具有可重用性,从而可以减少软件中的重复代码,避免重复编程。

三、面向对象中提出的对象概念更贴近现实,符合自然世界的规律,程序设计本来就是对现实世界的模拟,使用面向对象就能很自然的模拟出问题域。

四、对一个团队来说,使用面向对象思想编程,可以很容易的把项目的具体工作分离,分工合作,同时开发,从而降低了开发成本,提高了开发效率。

五、在面向过程程序中,许多重要的数据被放置在全局数据区,这样它们可以被所有的函数访问。这种结构很容易造成全局数据在无意中被其他函数改动,因而程序的正确性不易保证。面向对象程序设计的出发点之一就是弥补面向过程程序设计中的一些缺点:对象是程序的基本元素,它将数据和操作紧密地连结在一起,并保护数据不会被外界的函数意外地改变,这个就是面向对象的封装性。

 

以上是面向对象相对于面向过程的优点,但是面向对象也有不如面向过程之处。

 

一、对同一个问题域来说,面向对象程序的执行速度不如面向过程程序。在计算机速度飞速发展的今天,你可能会说,一丁点的性能牺牲没什么大不了。是的,从面向对象的角度,使的编程的结构更加清晰完整,数据更加独立和易于管理,性能的牺牲可以带来这么多的好处,没有理由不做稳赚的生意吧? 不过,在某些对速度要求极高特殊场合,例如你做的是电信的交换系统,每秒钟有超过百万的人同时进行电话交换,如果,每一个数据交换过程都是一个对象,那么总的性能损失将是天文数字。

二、面向对象程序中过多的继承属性,会导致存储问题。

不过话说回来,无论是面向对象那种如同描绘现实世界般的神奇画笔还是面向过程那种沉浸于流程和算法的脑力激荡都是我非常喜欢的,哈哈。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值