Difference between revisions of "Object Oriented Programming with Free Pascal and Lazarus/zh CN"

From Free Pascal wiki
Jump to navigationJump to search
m
m
Line 23: Line 23:
 
设想医院或医生办公室收集的血液样本的模拟。
 
设想医院或医生办公室收集的血液样本的模拟。
 
=== 血液样本 ===
 
=== 血液样本 ===
自然样本当然地是一个'''对象''';它有与之关联的许多信息,文档和其它自然对象。
+
实物样本当然地是一个'''对象''';它有与之关联的许多信息,文档和其它实物对象。
  
 
*由医生想要实施的测试决定类型的'''样本试管'''。
 
*由医生想要实施的测试决定类型的'''样本试管'''。
Line 54: Line 54:
 
**返回给医生。  
 
**返回给医生。  
  
The actual '''results''' are a record that the physician uses to assist the diagnosis, and a copy of the results is filed in the patient notes.
+
真实的'''结果'''是医生用来辅助诊断的纪录,它的拷贝填写在病人笔记里。
  
The physical sample might be retained for reference, confirmation or further tests, or might be disposed of by pouring down the sink or by incineration; there will be a method to describe this.
+
为了参考,确认或进一步的测试,实物样本可能被保留;或者可能被冲下洗涤槽或焚化;将有一个方法来描述这。
  
There is no need for a physician to spell out all the details and instructions every time a sample is collected; indeed, he may have very little knowledge of how the sample is processed in the lab. The details of the various processes are '''inherited''' from previous sample collections and analyses - there will be a generic plan for the whole sequence, and together we could think of the blood sample, all its documents and data, and the underlying methods, as a complex '''object'''.
+
每次收集样本时,医生不需要阐明所有的细节和指示;确实,他可能没有样本在实验室里如何处理的知识。各种处理的细节是从以前样本收集和分析'''继承'''的——整个顺序有一个通用计划,我们可以把血液样本,它的所有文档,数据和底层方法,当作一个复杂的'''对象'''
  
In the physician's mind, the blood sample is seen as almost the same entity as its results, and to the nurses and technicians the sample, the tube, the label and the storage conditions again form a single entity.
+
在医生的心里,血液样本看作和它的结果是一样的实体;对护士和技术人员来说,样本,试管,标签和存储条件组成一个单一实体。
=== Another Example - Automobile ===
+
=== 另外一个例子——汽车 ===
If you don't like blood, the same sort of reasoning could be applied to a car taken to a garage for repair.
+
如果你不喜欢血液,同样的推理顺序可以应用到放到车库里维修的卡车。
It might consist of:
+
它可能包括:
*the physical vehicle
+
*实物车辆
*documents held by the owner: registration or license (including license plates), insurance, receipts for purchase, parts, repairs etc
+
*所有者持有的文档:注册或执照(包括车牌),保险,购买收据,部件,维修等等
*the fuel consumption history
+
*燃油消耗历史
*the drivers allowed to use the vehicle, with their license particulars
+
*允许使用车辆的驾驶员,以及执照详情
*service records held by the garage
+
*车库持有的服务纪录
*methods or procedures to be followed for routine checking and maintenance
+
*例行检查和维修遵循的方法或过程
*methods to be followed for non-routine repairs etc
+
*非例行维修遵循的方法等等
*billing information for the customer
+
*客户的帐单信息
  
 
== Programming Example ==
 
== Programming Example ==

Revision as of 17:10, 2 January 2010

Template:FreePascal和Lazarus的面向对象编程

有许多Pascal的优秀教程,但是本教程尝试让初学者走得更远,进入面向对象编程,这是对Turbo-pascal,Delphi和FreePascal/Lazar提供的标准Pascal的扩展。

对象是对标准Pascal record结构的扩展

标准的基于文本的Pascal编程善于创建类似传统Unix应用,做一件事并且做得很好的应用。程序做的“一件事”可能是一个非常复杂的动作,可能给用户提供几个菜单驱动的选项,但是它本质上受限于服从用户在键盘上输入的命令,在终端或打印机上列出它的响应。

为了提供一个图形用户界面(GUI),通常要调用某种形式的面向对象编程方法(经常使用 C或它的变种,或Visual Basic,或诸如与或不与Lazarus一起使用的FreePascal的Pascal变种)。

在GUI里,有大量以结构化方式排列的图片,由与各种诸如下面行为关联的一系列工具或部件组成的屏幕代表用户。

  • 从菜单选择,
  • 打开或保存文件,
  • 连接Internet,
  • 执行数字计算,等等。

预期用户在屏幕上移动鼠标或其它光标/选择工具,选择对应鼠标按钮点击或按键执行的行为。

当处理复杂图形用户界面的系统可以用标准Pascal或大多数任意其它编程语言编写时,那么更容易使用一个面向对象系统,在这样的系统里,屏幕上的每个图形对象可以有以通常结构保存在一起的所有属性,与用法关联的过程和函数。


对象——一个现实世界模拟

设想医院或医生办公室收集的血液样本的模拟。

血液样本

实物样本当然地是一个对象;它有与之关联的许多信息,文档和其它实物对象。

  • 由医生想要实施的测试决定类型的样本试管
  • 指示护士或技术员收集样本的本地规则 (或方法标准操作过程)
    • 使用哪类试管,
    • 如何处理样本
    • 在转移到实验室之前如何存储它。
  • 试管上有下列细节的标签
    • 样本标识
    • 病人姓名和生日
    • 收集日期和时间
    • 需要的测试。
  • 与样本一起到实验室的申请表,表明
    • 样本标识
    • 申请医生的标识
    • 医生申请的测试以及
    • 给出的病人的充分详情
    • 寻求可能诊断的确认。

申请表的拷贝放在病人笔记里,提醒医生在合适时间里得到结果。

  • 在实验室里——本地方法决定
    • 如何分析样本,
    • 使用哪台机器,
    • 机器如何校准和操作,
    • 结果如何存储,格式化以及
    • 返回给医生。

真实的结果是医生用来辅助诊断的纪录,它的拷贝填写在病人笔记里。

为了参考,确认或进一步的测试,实物样本可能被保留;或者可能被冲下洗涤槽或焚化;将有一个方法来描述这。

每次收集样本时,医生不需要阐明所有的细节和指示;确实,他可能没有样本在实验室里如何处理的知识。各种处理的细节是从以前样本收集和分析继承的——整个顺序有一个通用计划,我们可以把血液样本,它的所有文档,数据和底层方法,当作一个复杂的对象

在医生的心里,血液样本看作和它的结果是一样的实体;对护士和技术人员来说,样本,试管,标签和存储条件组成一个单一实体。

另外一个例子——汽车

如果你不喜欢血液,同样的推理顺序可以应用到放到车库里维修的卡车。 它可能包括:

  • 实物车辆
  • 所有者持有的文档:注册或执照(包括车牌),保险,购买收据,部件,维修等等
  • 燃油消耗历史
  • 允许使用车辆的驾驶员,以及执照详情
  • 车库持有的服务纪录
  • 例行检查和维修遵循的方法或过程
  • 非例行维修遵循的方法等等
  • 客户的帐单信息

Programming Example

Enough of this pre-occupation with Real-World examples! Let us proceed to the main purpose: programming in FreePascal.

Let us consider the creation of a simple Form with a few controls for an application in FreePascal/Lazarus.

ObjectInspector-TForm.png
BlankForm.png

On invoking the Lazarus IDE, the programmer is presented with a blank template Form design, on which he is encouraged to place various controls or objects.

Note that the pre-made blank Form is already an Object, with its own properties such as position (Top and Left), size (Height and Width), colour, default font for adding text etc.



If a Button control is placed on the Form (type TButton), it will have its own series of properties, which can be examined in the Object Inspector window.

Several of the properties have names similar to those for the Form; this is because many properties are Inherited from some common Ancestor class, which lays out how properties are to be defined and handled by the descendant classes.

As well as properties, the Object Inspector offers a tab called Events, which gives access to Event Handlers which are methods instructing the application how to deal with things such as a mouse click on a button (OnClick) or some change in the position, size or other properties (OnChange).

The physical image of the Button on the Form, together with all its properties and Event Handler methods, should be regarded as a single entity or Object in Pascal.

ObjectInspector-TButton.png
FormWithButton.png
Source FormWithButton1.png

Object-Oriented Extensions to standard Pascal

The Pascal record structure is extended by defining an

Object

An Object is a special kind of record. The record contains all the fields that are declared in the object's definition (just like a conventional record), but now procedures and functions can be declared as if they were part of the record and are held as pointers to the methods associated with the object's type.

For example, an object could contain an array of real values, together with a Method for calculating the average.

Type
  Average = Object
    NumVal: Integer;
    Values: Array [1..200] of Real;
    Function Mean: Real; { calculates the average value of the array }
  End;

Objects can ”inherit” fields and methods from ”parent” objects. This means that these fields and methods can be used as if they were included in the objects declared as a ”child” object.

Furthermore, a concept of visibility is introduced: fields, procedures and functions can be declared as public, protected or private. By default, fields and methods are public, and can be exported outside the current unit. Protected fields or methods are available only to objects descended from the current ancestor object. Fields or methods that are declared private are only accessible in the current unit: their scope is limited to the implementation of the current unit.

Class

Objects are not used very often by themselves in FreePascal and Lazarus; instead, Classes are used very widely. A Class is defined in almost the same way as an Object, but is a pointer to an Object rather than the Object itself. Technically, this means that the Class is allocated on the Heap of a program, whereas the Object is allocated on the Stack.

Here is a simple example of a typical Class declaration:

{-----------------------------------------}
{example of Class declaration from the LCL}
{-----------------------------------------}
 TPen = class(TFPCustomPen)
 private
   FColor: TColor;
   FPenHandleCached: boolean;
   FReference: TWSPenReference;
   procedure FreeReference;
   function GetHandle: HPEN;
   function GetReference: TWSPenReference;
   procedure ReferenceNeeded;
   procedure SetHandle(const Value: HPEN);
 protected
   procedure DoAllocateResources; override;
   procedure DoDeAllocateResources; override;
   procedure DoCopyProps(From: TFPCanvasHelper); override;
   procedure SetColor
        (const NewColor: TColor; const NewFPColor: TFPColor); virtual;
   procedure SetFPColor(const AValue: TFPColor); override;
   procedure SetColor(Value: TColor);
   procedure SetMode(Value: TPenMode); override;
   procedure SetStyle(Value: TPenStyle); override;
   procedure SetWidth(value: Integer); override;
 public
   constructor Create; override;
   destructor Destroy; override;
   procedure Assign(Source: TPersistent); override;
   property Handle: HPEN read GetHandle write SetHandle; deprecated;
   property Reference: TWSPenReference read GetReference;
 published
   property Color: TColor read FColor write SetColor default clBlack;
   property Mode default pmCopy;
   property Style default psSolid;
   property Width default 1;
 end;


Note that this class is defined as an instance of another parent or ancestor class (TFPCustomPen) from which it inherits all its properties and methods. It has some fields of its own, grouped under

  • private - this means that items defined here are only available or visible to other classes or procedures/function defined within the same program unit (this example is from Graphics, so any of the other classes such as TBitMap, TPicture etc in the same unit can use them). They are essentially local variables (eg FColor, FPenHandleCached) or locally used methods (GetHandle, SetHandle) but can be used or referred to in items declared in the protected or public sections.
  • protected - this means that items defined here are only available or visible to classes that are descended from this ancestor class, and inherit its properties or methods
  • public - this means that items defined here are available to any programming unit that includes the current unit in its Uses clause
  • published - is the same as a public section, but the compiler also generates type information that is needed for automatic streaming of these classes. Often the list of published items appear in the Object Inspector of Lazarus; if there is no published list, all the public fields usually appear in the Object Inspector.

Methods

A method is just like a standard procedure or function, but can have some additional directives.

Some of the methods defined above are labelled with the directive virtual; others are labelled with the override directive.

  • virtual means that the type or actual instance of a method is not known at compile-time, but is selected at run-time depending on what sub-program actually calls the method. It could be considered a place-holder in the definition of the class.
  • override means that at run-time the locally given definition can take the place of a definition inherited from an ancestor class, particularly if it was virtual. If you particularly want to use the method defined in the ancestor class, it is sometimes necessary to call it specifically with the inherited clause.

Methods with no virtual or override directive are static methods (the usual kind in Pascal). Those with a virtual or override directive are dynamic.

Special instances of methods are:

  • create - a constructor for a class, which takes care of allocating memory, collecting together all the information needed and configuring/initializing the various properties.
  • destroy - a destructor for a class, which removes all the parts of the class from the system in an orderly and logical way, and returns all its resources for the system to re-use.

Properties

Properties are just like ordinary fields in a conventional Pascal record, but they can have read and/or write specifiers.

  • read specifier is a field, or a function that returns a result of the correct type for the property. In the example above, the property Color has a read specifier FColor, which is a local variable containing the value to be used. If a property has a read but no write specifier, it is read-only.
  • write specifier is a field, or a procedure that will store the value of the property in a specific location. In the example above, Color has a write specifier SetColor that is a procedure (defined in the protected section) for writing the color value to some specified location. If a property has a write but no read specifier, it is write-only.
  • default - note that it is possible to set a default value for a property. For example, Color here is given the default value clBlack, or black, at the time of creation. It could subsequently be given a different value, by a programming assignment statement, or in the Object Inspector.


Further information

This has only scratched the surface of the topic. For more details, readers are strongly recommended to read the FreePascal manuals, especially Chapters 5 (Objects) and 6 (Classes)

--Kirkpatc 11:04, 20 July 2008 (CEST)


Console Mode Pascal