
就如何利用面向对象的软件开发方法来开发软件心得体会
面向对象技术是软件技术的一次革命,在软件开发史上具有里程碑的意义。
随着OOP(面向对象编程)向OOD(面向对象设计)和OOA(面向对象分析)的发展,最终形成面向对象的软件开发方法 OMT(LbjectModellingTechnique)。
这是一种自底向上和自顶向下相结合的方法,而且它以对象建模为基础,从而不仅考虑了输入、 输出数据结构,实际上也包含了所有对象的数据结构。
所以OMT彻底实现了PAM没有完全实现的目标。
不仅如此,OO技术在需求分析、可维护性和可靠性这三 个软件开发的关键环节和质量 指标上有了实质性的突破,彻底地解决了在这些方面存在的严重问题,从而宣告了软件危机末日的来临。
自底向上的归纳 OMT的第一步是从问题的陈述入手,构造系统模型。
从真实系统导出类的体系,即对象模型包括类的属性,与子类、父类的继承关系,以及类之间的关 联。
类是具有相似属性和行为的一组具体实例(客观对象)的抽象,父类是若干子类的归纳。
因此这是一种自底向上的归纳过程。
在自底向上的归纳过程中,为使子 类能更合理地继承父类的属性和行为,可能需要自顶向下的修改,从而使整个类体系更加合理。
由于这种类体系的构造是从具体到抽象,再从抽象到具体,符合人类 的思维规律,因此能更快、更方便地完成任务。
这与自顶向下的Yourdon方法构成鲜明的对照。
在Yourdon方法中构造系统模型是最困难的一步,因为 自顶向下的“顶”是一个空中楼阁,缺乏坚实的基础,而且功能分解有相当大的任意性,因此需要开发人员有丰富的软件开发经验。
而在OMT中这一工作可由一般 开发人员较快地完成。
在对象模型建立后,很容易在这一基础上再导出动态模型和功能模型。
这三个模型一起构成要求解的系统模型。
自顶向下的分解 系统模型建立后的工作就是分解。
与Yourdon方法按功能分解不同,在OMT中通常按服务(Service)来分解。
服务是具有共同目标的相关 功能的集合,如I/O处理、图形处理等。
这一步的分解通常很明确,而这些子系统的进一步分解因有较具体的系统模型为依据,也相对容易。
所以OMT也具有自 顶向下方法的优点,即能有效地控制模块的复杂性,同时避免了Yourdon方法中功能分解的困难和不确定性。
OMT的基础是对象模型 每个对象类由数据结构(属性)和操作(行为)组成,有关的所有数据结构(包括输入、输出数据结构)都成了软件开发的依据。
因此Jackson方法 和PAM中输入、输出数据结构与整个系统之间的鸿沟在OMT中不再存在。
OMT不仅具有Jackson方法和PAM的优点,而且可以应用于大型系统。
更重 要的是,在Jackson方法和PAM方法中,当它们的出发点——输入、输出数据结构(即系统的边界)发生变化时,整个软件必须推倒重来。
但在OMT中系 统边界的改变只是增加或减少一些对象而已,整个系统改动极小。
需求分析彻底 需求分析不彻底是软件失败的主要原因之一。
即使在目前,这一危险依然存在。
传统的软件开发方法不允许在开发过程中用户的需求发生变化,从而导致种种问题。
正是由于这一原 因,人们提出了原型化方法,推出探索原型、实验原型和进化原型,积极鼓励用户改进需求。
在每次改进需求后又形成新的进化原型供用户试用,直到用户基本满意,大大提高了软件的 成功率。
但是它要求软件开发人员能迅速生成这些原型,这就要求有自动生成代码的工具的支持。
OMT彻底解决了这一问题。
因为需求分析过程已与系统模型的形成过程一致,开发人员与用户的讨论是从用户熟悉的具体实例(实体)开始的。
开发人员必须搞清现实系统才能导出系统模型,这就使用户与开发人员之间有了共同的语言,避免了传统需求分析中可能产生的种种问题。
可维护性大大改善 在OMT之前的软件开发方法都是基于功能分解的。
尽管软件工程学在可维护方面作出了极大的努力,使软件的可维护性有较大的改进。
但从本质上讲,基于功能分解的软件是不易 维护的。
因为功能一旦有变化都会使开发的软件系统产生较大的变化,甚至推倒重来。
更严重的是,在这种软件系统中,修改是困难的。
由于种种原因,即使是微小的修改也可能引入 新的错误。
所以传统开发方法很可能会引起软件成本增长失控、软件质量得不到保证等一系列严重问题。
正是OMT才使软件的可维护性有了质的改善。
OMT的基础是目标系统的对象模型,而不是功能的分解。
功能是对象的使用,它依赖于应用的细节,并在开发过程中不断变化。
由于对象是客观存在的,因此当需求变化时对象的性质要比对象的使用更为稳定,从而使建立在对象结构上的软件系统也更为稳定。
更重要的是OMT彻底解决了软件的可维护性。
在OO语言中,子类不仅可以继承父类的属性和行为,而且也可以重载父类的某个行为(虚函数)。
利用这 一特点,我们可以方便地进行功能修改:引入某类的一个子类,对要修改的一些行为(即虚函数或虚方法)进行重载,也就是对它们重新定义。
由于不再在原来的程 序模块中引入修改,所以彻底解决了软件的可修改性,从而也彻底解决了软件的可维护性。
OO技术还提高了软件的可靠性和健壮性。
1、 总结一下面向对象编程(OOP)的基本特征。
面向对象三大特性:封装,继承,多态面向对象(Object Oriented,缩写为OO)是现代软件技术的精髓。
从早期的SmallTalk到如日中天的Java,都渗透着面向对象思想。
OO具有三大特性:封装性、继承性和多态性。
想掌握面向对象思想,就必须深入理解 其三大特性。
这里我尽量少谈概念,只用一个生活中的例子和一段代码来解释它们。
1、封装性(Encapsulation) 所谓封装,就是将某些东西包装和隐藏起来,让外界无法直接使用,只能通过某些特定的方式才能访问。
OO将万物都视为“对象”(Object),任何对象都具有特性和行为。
我们将其特性称为“成员变量” (MemberVarible),将其行为称之为“成员函数(Member Function),被封装的特性只能通过特定的行为去访问。
大家都见过旅馆里常用的一种茶叶吧,就是用纸袋把茶叶包装起来再系是一根线。
用的时候只需要将其放在水杯里泡就行。
这样的好处是不会将茶叶渣和茶垢弄的满杯子都是。
好
这就是一个封装的例子。
我们喝茶的目的是享受茶叶的香冽;所以茶叶的味道(Flavour)就是茶叶所具有的最 重要特性之一;可是我们无法直接享受它的清香,因为被外面的纸袋“封装”起来了。
唯一的办法就是“泡”(Dilute),将茶袋扔在开水中泡,它的味道就出来了,融入水中。
如果我们把袋装茶叶看作一个对象的话,它提供了成员变量Flavour和成员函数Dilute 。
并且Flavour是私有(Private)的,我们不能直接把它吞进肚子去,而只能通过成员函 数Dilute才能享受Flavour。
下面用C++代码来描述这个例子: Class CTea { Private: Cstring m_Flavour; \\\/\\\/味道 Cstring m_Color; \\\/\\\/颜色 ...... \\\/\\\/等等其它属性 Private: Void CTea(); \\\/\\\/构造函数 Void ~CTea(); \\\/\\\/析构函数 Public: Cstring Dilute();\\\/\\\/沏茶 ...... \\\/\\\/等等其它方法 } Cstring CTea::Dilute() { \\\/\\\/怎样泡出味道来的代码 } 这就是封装。
通过将对象的某些属性声明为Private隐藏起来,只能使用其提供的特定 方法去访问。
2、继承(Inheritance) 如果只是封装,那么非面向对象语言也能部分的做到。
比如在C中,用结构(Struct)、VB中用自定义类型(Type)也能封装一些变量。
OO最有吸引力的特性是继承。
通俗的说后代具有祖先的某些特点就叫继承,当然后代还可以具有自己独有的特征。
举个例子吧,菜刀。
菜刀(cutlery)是钢(Steel)做的,钢是一种金属(Metal),金属则是大千世界里的一种物质(Substance)。
所以菜刀的一些特性可以追溯到物质具有的一般属性。
正是因为这个道理,MFC中所有类均从CObject继承而来。
这就是继承。
菜刀直接继承了钢的特性,钢又继承了金属的特性,......下面的代码描 述了这种复杂而有独特的继承关系: Class CSubstance { Private: int m_color; void CSubstance(); void ~CSubstance(); \\\/\\\/......(我是学文科的,具体属性说不上来) } Class CMetal:Public CSubstance { void CMetal(); void ~CMetal(); \\\/\\\/...... } Class CSteel:Public CMetal { void CSteel(); void ~CSteel(); \\\/\\\/...... } Class CCutlery:Public CSteel { private: Cstring m_Blade; void CCutlery(); void ~CCutlery(); \\\/\\\/...... Public: void Cut(); } 这里,CSubstance被称为基类(Base class),其它被称为衍生类(Derived class)。
衍生类与基类是“Is kind of”的关系。
子类与其祖先类之间复杂的函数调用关系不在本文讨论之列。
继承是一种树状的层次关系。
子类在继承祖先类的成员变量和成员函数的同时也可以 定义自己的成员变量和成员函数。
比如,Metal 除了继承了Substance的一般特性外,还具有自己的属性诸如可延展性;CCutlery在继承CSteel的特性后还具有自己的成员诸如“刀刃”(Blade)、“锋利”(Sharpness)、行为有如“切”(Cut)等。
面向对象技术是对现实生活的抽象,你可以用生活中的经验去思考程序设计的逻辑。
3、多态性(Polymorphism) 讨论多态之前先要明白什么是“虚拟”(Virtual)。
C++\\\/MFC就是用虚拟这种方式实现多态的。
为什么“虚拟”这个概念
看下边的例子: Class Cincect \\\/\\\/昆虫类 { private: int m_foot; \\\/\\\/脚的数量 ...... \\\/\\\/其它成员变量 private: void Cincect(); void ~Cincect(); public: void Bite()\\\/\\\/咬人 { ...... \\\/\\\/怎样咬人的代码,比如张开嘴啃 } } 我把Bite(咬)这个动作在基类中定义为一般化动作。
可是,不是所有昆虫咬 人的方法都一样(况且还有的根本就不咬人呢,比如蜻蜓),比如蚊子是用嘴那个 吸管叮人而蚂蚁是用嘴去夹。
从昆虫这个类别衍生出以下两个类别:Cant(蚂蚁)、Cmosquito(蚊子)。
class Cant :public Cincect \\\/\\\/蚂蚁类 { ...... } class Cmosquito :public Cincect \\\/\\\/蚊子类 { ...... } 它们都继承了Cincect的所有成员,当然也继承了Bite()这个动作。
现在就有问题了: 同样继承自昆虫,当我们使用Bite()这个动作时怎么才能区分蚂蚁和蚊子各自的独有的咬人方式呢
方法之一是用“::”符号指明具体引用的是那一个,但这样明显失去了灵活性; 另一种方法就是“虚拟”。
使用关键字virtual将Bite()声明为虚拟函数,然后在每个 衍生类中重新定义,描述它们各自的咬人方法,调用的时候也不会都一种结果啦。
于是上边的例子可以改写为: Class Cincect \\\/\\\/昆虫类 { private: int m_foot; \\\/\\\/脚的数量 ...... \\\/\\\/其它成员变量 private: void Cincect(); void ~Cincect(); public: virtual Bite(){}\\\/\\\/咬人,但我们只声明这个成员函数, \\\/\\\/却让它什么动作都不做,让衍生类自己去定 \\\/\\\/义各自的咬人方法 } class Cant :public Cincect \\\/\\\/蚂蚁类 { ...... virtual Bite(); } Cant::Bite() { ...... \\\/\\\/蚂蚁具体的咬人方式 } class Cmosquito :public Cincect \\\/\\\/蚊子类 { ...... virtual Bite(); } Cmosquito::Bite() { ...... \\\/\\\/蚊子具体的咬人方式 } 所以,虚拟的目的是只在基类中将一般化动作声明一个成员函数的原型而不做 具体定义,让衍生类自己去定义。
这就是面向对象的特征之三:多态性。
基类的同一个成员在不同的衍生类中可以具 有不同的形态,更好地抽象和描述大千世界中的诸多“对象”。
1.了解什么是多态性 2.如何定义一个虚方法 3.如何重载一个虚方法 4.如何在程序中运用多态性 面向对象程序设计中的另外一个重要概念是多态性。
在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。
可以把一组对象放到一个数组中,然后调用它们的方法,在这种场合下,多态性作用就体现出来了,这些对象不必是相同类型的对象。
当然,如果它们都继承自某个类,你可以把这些派生类,都放到一个数组中。
如果这些对象都有同名方法,就可以调用每个对象的同名方法。
本节课将向你介绍如何完成这些事情。
1.清单9-1. 带有虚方法的基类:DrawingObject.cs using System; public class DrawingObject { public virtual void Draw() { Console.WriteLine(I'm just a generic drawing object.); } } 说明 清单9-1 定义了DrawingObject类。
这是个可以让其他对象继承的基类。
该类有一个名为Draw()的方法。
Draw()方法带有一个virtual修饰符,该修饰符表明:该基类的派生类可以重载该方法。
DrawingObject类的 Draw()方法完成如下事情:输出语句I'm just a generic drawing object.到控制台。
2.清单9-2. 带有重载方法的派生类:Line.cs, Circle.cs, and Square.cs using System; public class Line : DrawingObject { public override void Draw() { Console.WriteLine(I'm a Line.); } } public class Circle : DrawingObject { public override void Draw() { Console.WriteLine(I'm a Circle.); } } public class Square : DrawingObject { public override void Draw() { Console.WriteLine(I'm a Square.); } } 说明 清单9-2定义了三个类。
这三个类都派生自DrawingObject类。
每个类都有一个同名Draw()方法,这些Draw()方法中的每一个都有一个重载修饰符。
重载修饰符可让该方法在运行时重载其基类的虚方法,实现这个功能的条件是:通过基类类型的指针变量来引用该类。
3.清单9-3. 实现多态性的程序:DrawDemo.cs using System; public class DrawDemo { public static int Main(string[] args) { DrawingObject[] dObj = new DrawingObject[4]; dObj[0] = new Line(); dObj[1] = new Circle(); dObj[2] = new Square(); dObj[3] = new DrawingObject(); foreach (DrawingObject drawObj in dObj) { drawObj.Draw(); } return 0; } } 说明 清单9-3演示了多态性的实现,该程序使用了在清单 9-1 和清单9-2中定义的类。
在DrawDemo类中的Main()方法中,创建了一个数组, 数组元素是DrawingObject 类的对象。
该数组名为dObj,是由四个DrawingObject类型的对象组成。
接下来, 初始化dObj数组, 由于Line, Circle和Square类都是DrawingObject类的派生类,所以这些类可以作为dObj数组元素的类型。
如果C#没有这种功能,你得为每个类创建一个数组。
继承的性质可以让派生对象当作基类成员一样用,这样就节省了编程工作量。
一旦数组初始化之后,接着是执行foreach循环,寻找数组中的每个元素。
在每次循环中, dObj 数组的每个元素(对象)调用其Draw()方法。
多态性体现在:在运行时,各自调用每个对象的Draw()方法。
尽管dObj 数组中的引用对象类型是DrawingObject,这并不影响派生类重载DrawingObject 类的虚方法Draw()。
在dObj 数组中,通过指向DrawingObject 基类的指针来调用派生类中的重载的Draw()方法。
输出结果是: I'm a Line. I'm a Circle. I'm a Square. I'm just a generic drawing object. 在DrawDemo 程序中,调用了每个派生类的重载的Draw()方法。
最后一行中,执行的是DrawingObject类的虚方法Draw()。
这是因为运行到最后,数组的第四个元素是DrawingObject类的对象。
小结 现在对多态性有所了解之后,你可以在派生类中,实现一个重载基类虚方法的方法。
虚方法和重载的派生类方法之间的关系就体现出C#的多态性。
java高手帮忙总结下java面向对象高级篇的一些内容
1.继承:继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法。
对象的一个新类可以从现有的类中派生,这个过程称为类继承。
新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类)。
派生类可以从它的基类那里继承方法和实例变量,并且类可以修改或增加新的方法使之更适合特殊的需要。
2.多态性:多态性是指允许不同类的对象对同一消息作出响应。
多态性包括参数化多态性和包含多态性。
多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好的解决了应用程序函数同名问题。
3.封装:封装是把过程和数据包围起来,对数据的访问只能通过已定义的界面。
面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。
4.字符串处理:为了节省空间而特别对字符串做了处理的类StringBuffer和StringBuilder5.抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。
抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节。
抽象包括两个方面,一是过程抽象,二是数据抽象。
6.为了处理运行时候异常和编译时异常而做出的机制.7.就是数组的升级版本,集合底层也是数组.但集合可以放多种类型而不只是一种基本类型.集合还能更方便快速的增删查改该集合里面的数据
VC++的面向对象 用自己的语言总结面向对象
oop只有语言才会具有的性质,VC 仅仅是编程ide。
面对对象是解决问题的一种思想,现在逐渐的流行起来,它有它的优势。
如果你想造自行车,你必须要从零件造起,组装,运行。
oop提供了这样的一个思路,我这个厂家造轮子,造骨架,造把手,你只需要把同规格的组装就可以用,不用什么东西自己动手来。
它提供一个标准,你按照标准来。
大家分工合作,你需要我,我给你造完提供成品。
我不需要知道是谁用,我只知道我是干这个干好就可以。
面对过程不同,你得考虑我先干什么在干什么然后干什么最后完成什么样东西出来一个自行车。
面对对象体现分工合作,面对过程提供一条线完成工作。
计算机语言中,两个都有利弊。
现在更趋向oop,这样代码重用效率高,易于维护和排除错误,条例清晰。
如果你写一个大项目你就会充分了解两个的不同。
你会问C语言的函数不也是提供分块解决
可是,在很多对象面前,会变混乱,你的函数命名
你的代码重用
等等…于是Cplusplus出现了clss 这个好东西。
慢慢会懂的。
java中面向对象怎么理解
最好是自己的理解
面向对象:用线性的思维。
与面向过程相辅相成。
在软件开发过程中,宏观上,用面向对象来把握事物间复杂的关系,分析系统。
微观上,仍然使用面向过程。
“面向过程”是一种是事件为中心的编程思想。
就是分析出解决问题所需的步骤,然后用函数把这写步骤实现,并按顺序调用。
”面向对象“是以“对象”为中心的编程思想。
简单的举个例子:汽车发动、汽车到站。
汽车启动是一个事件,汽车到站是另一个事件,面向过程编程的过程中我们关心的是事件,而不是汽车本身。
针对上述两个事件,形成两个函数,之后依次调用。
对于面向对象来说,我们关心的是汽车这类对象,两个事件只是这类对象所具有的行为。
而且对于这两个行为的顺序没有强制要求。
面向过程的思维方式是分析综合,面向对象的思维方式是构造。
面向对象分析方法的步骤和特点
使用MVC进行项目开发已经有一段时间了,在这段时间里感触最深的就是自己对宏观性面向对象分析方法的缺乏。
面向对象分析是当今流行的系统分析方法之一,下面就谈谈在做项目的过程中我的一些小经验。
在面对简单系统时程序员可以很顺利的提出问题的解决方案,并且一般情况下都是可行的。
这是由于问题域关系简单,所涉及到的内部构造、联系比较容易解释。
而对于当前越来越复杂的系统,其问题域也就显示的越来越复杂,而且内部的关系也不是很容易解释,有些大的系统常常超出了人的解决问题的能力。
在这种情况下,以往的面对过程的解决方法已经不能满足日益增长的复杂系统分析的需要,在这种情况下,面向对象的分析方法就显得尤为总要了。
在面向对象设计领域中,在横向上把问题域分为数个不同的、低耦合、高内聚的问题域,而在纵向上又继续分解各个不同的小的问题域,最后分解为叶节点问题域,从而解决问题。
在面对对象分析方法中,用数个对象间的消息传递来完成整个问题。
下面看一看复杂系统的5个属性:1. 杂性经常是以层次的形式表现出来,复杂系统是由相互关联的子系统组成,而这些子系统又是由他们各自的子系统构成,并由此类推到最底层的基本构件。
2. 对系统中最基本的构件的选择是任意的,而且在很大程度上取决于系统观察者的判断力。
3. 一般而言,各构件内的连接总是要强于构件间的连接。
在从构件的低频动态中分离出高频动态时,这一属性是相当有用的。
这是因为高频动态涉及到各部件的内部结构,而低频动态涉及到构件间的交互。
4. 层次系统通常都是由仅仅少数不同的子系统通过不同的排列组合方式组成。
5. 我们发现正运行的复杂系统总是由以前运行的简单系统演化而来……任何胡乱凑合设计出来的复杂系统都不可能正常运转,也不可能被修补好。
我们必须由运行中的简单系统开始。
对于第一点,正像我上面所说的那样,系统是层次结构的。
能够给一个复杂的系统进行正确的层次分析,才能够保证对系统的正确估计,包括可行性、可维护性、可扩展性……等等。
而且对于日后对该系统进行维护(maintenance)、演化(evolution)、维持(preservation)都能够很好的支持。
对于其中的第二点,强调了观察者的判断力,其实我认为其中也包括观察者的身份角度。
对于一个系统而言,观察者并不是只进行分析设计的工程师,编码阶段的程序员,还应该包括用户等所有这些同该系统有关的人员。
作为不同的人员,对于系统就有不同的观察点、观察角度、身份等特殊因素。
因此在不同身份的人(指参与者)甚至同一身份的人眼中说观察到的系统特性都是不尽相同的。
在大学里大家都接触过透明性的概念,这就是不同观察者所观察角度不同的直观反应。
对于用户来说,基本上底层的操作、算法、通讯对于他们来说都是透明的,他们根本不用理会(其实也不知道)内部用了什么。
而对于一个负责某模块的程序员来说就不会考虑其他模块的实现,对于他们来说其他模块是透明的,他们只需要负责管理好提供的模块接口就OK了。
对于第三点,讲的就是面对对象分析设计的方向,在面对对象分析设计系统时,被分解的各个模块一定要做到高内聚、低耦合。
有良好高内聚、低耦合系统常常会很容易维护,一个地方改动通常不需要牵扯到大的改动,维护行强。
而且对于像VC程序这种更要求效率的程序来说,高内聚、低耦合也可以提高程序的运行期效率,应为对象内部的调用一般情况下会相比模块间的调用占用更少的执行时间,这样将高频动态封装在一个对象内部就会一定程度上提高程序运行期执行效率。
第四点则说明了面向对象程序设计对程序设计可复用性的优点。
在这点中所“层次系统由仅仅少数不同的子系统构成”那么多数子系统在不同的复杂系统中都是能够重复使用的。
比如说建筑一栋大厦和建筑桥梁,虽然两者都是复杂的系统,但是对于其结构中就会有很多相似甚至相同之处,没有必要建筑好大厦回头建筑桥梁的时候又要重新设计每一快砖瓦。
第五点提醒我们在系统设计时,尽量使用以往能够正常运行的子系统来重新构件新的系统。
这一点不仅说明第四点中的复用性,而且也说明了一个我们常常要犯的错误。
就是将并没有通过严格测试的子系统,匆忙的加入到大系统中,这样做不利于对系统的基层,常常引入了其他错误,使得系统频频崩溃,最严重会导致系统的重新分析。
这是我对面向对象的一点心得体会,虽然我们大家在平时工作中所面对的问题、问题域不同,使用的开发工具不同,但是面向对象是一种思维方式,有利于分析、解决问题的一种方法,并不和任何语言挂钩(当然语言对于面向对象特性的支持程度有所不同)。
所以希望各位同事能够尽量使用科学的方法分析解决问题,形成一种设计模式,以供大家互相交流。
软件设计是一种艺术,也是一门工程学。



