F#入门-第四章 面向对象-第四节 封装

来源:互联网 发布:我们相爱吧网络直播 编辑:程序博客网 时间:2024/05/16 14:38

    面向对象的优点之一为封装。封装是指将对象内部的数据与行为隐藏起来,只对外公开外部所需要用到的信息。

    在本节中,介绍为了进行封装而使用到的功能之一访问控制。

    作为示例,让我们来看吃豆子游戏,该游戏中小人在方格块中进行游走。这里,如果使用前节介绍的Point类型,那么可能需要考虑增加表示两点之间距离的函数distance,例如这样

定义了距离的Point类
type Point = {mutable x : int; mutable y : int}
    with
        member v.abs (x:int) =
            if x>=0 then x else -x
        member v.distance (p:Point) =
            abs(p.x - v.x) + abs(p.y - v.y);
    end;;


    这个例子中为了执行distance测量距离,定义了辅助函数abs。但是,如果就这样将Point类型进行公开,外部不仅可以调用distance函数,也可以调用原本不想给外部调用的函数abs了。

外部非法调用函数
Console.WriteLine (p.abs 10);;  


    到了后来,为了让外部只能调用distance函数,不得不将abs函数删除而改用别的方法来实现abs函数中的处理。但是因为很可能外部程序许多地方都使用着该函数,该函数被擅自删除后外部使用到该函数的地方就全部出错了。

    针对这种情况,使用访问控制可以控制外部不会访问到类内部不想被公开的部分。

    访问控制有三种方式。
    public
    类内全部公开
    基本上所有数据类型和字段
    internal
    在程序集(DLL或EXE)内部全部公开
    private
    只在类型定义或模块内公开

    举例说明如下

 

访问控制
open System;;
type Point = {mutable x : int; mutable y : int}
    with
        member private v.abs (x:int) =
            if x>=0 then x else -x
        member v.distance (p:Point) =
            abs(p.x - v.x) + abs(p.y - v.y);
    end;;
let p = {x=10;y=10} in
let q = {x=20;y=20} in
Console.WriteLine (p.distance q); //OK
Console.WriteLine (p.abs 10);; //错误


    由于abs方法前面加上了private关键字,从Point类型定义之外就不能访问到abs方法了。

    在F#中几乎任何地方都可以使用访问控制。可使用场所基本如下
    成员定义,类定义,结构体定义。
    new(..)对象构造器定义。
    模块定义内部的let,module,type,extern声明与类定义中的模式中每一个识别符

    如果写出来的程序只供自己使用,那么访问控制好像并没有如此重要,但是,在书写对外公开的类库等情况下,就一定要对访问控制特别留意了。