F#程序设计-面向对象编程之访问修饰符

来源:互联网 发布:脑洞故事知乎 编辑:程序博客网 时间:2024/06/08 10:19

封装是类的一大特性,它把抽象的、复杂的事物封装了在内部,调用者无法看到它的内部操作。然而,由于类的调用者能够接触到类暴露出来的任何属性和方法,也能够随意的修改类的属性,改变类的状态,这也导致意外的BUG出现。幸好,F#与.NET其他的语言一样,对于类的属性和方法提供了可访问控制,允许用户可以操作哪些方法或者属性。

F#的可访问修饰符跟其它的.NET语言一样,提供了private、public、internal三种修饰符,但没有了其它语言具有的protect。下面的示例新建了一个类Ruby类,类的访问修饰符为internal,说明它只在所内的程序集内被其它类访问,同时它的主构造函数为private,其它的构造函数为public:

type internal Ruby private(shininess, carats) =
            let mutable m_size = carats
            let mutable m_shininess = shininess
          
            member this.Polish() =
                this.Size <- this.Size - 0.1
                m_shininess <- m_shininess + 0.1
          
            member public this.Size with get () = m_size
            member private this.Size with set newSize = m_size <- newSize
            member this.Shininess = m_shininess
            public new() =
                let rng = new Random()
                let s = float (rng.Next() % 100) * 0.01
                let c = float (rng.Next() % 16) + 0.1
                new Ruby(s, c)
            public new(carats) =
                let rng = new Random()
                let s = float (rng.Next() % 100) * 0.01
                new Ruby(s, carats)

 

在F#中,定义的类型、值、函数默认是public的,而类在字段(无论是let绑定还是val申明的)默认都是private的,下面的列出了三种访问修饰符的作用以及使用范围:

 

public:将一个方法、属性标记为可以在任何地方访问,在F#中,如果类型、值、函数没有任何标记访问修饰符,默认都是public的

private:private限制了值、方法、属性仅仅只能在类的内部访问,也不能被外部访问,就算是派生类也不行。类的字段默认是private的

internal:跟public修饰符一样,但是它定义了只能被同一程序集内的类型所访问,但不能被程序集外的任何类型访问

 

可访问修饰符不仅仅可以用于类,也可以用于模块,在模块中运用可访问修饰符跟在类中是一样的,例如:

open System.IO
open System.Collections.Generic
module Logger =
    let mutable private m_filesToWriteTo = new List<string>()
    let AddLogFile(filePath) = m_filesToWriteTo.Add(filePath)
    let LogMessage(message : string) =
        for logFile in m_filesToWriteTo do
            use file = new StreamWriter(logFile, true)
            file.WriteLine(message)
            file.Close()

 

可访问修饰符关键是作用范围的限制和封装,但是在每个类型、方法、值中增加访问修饰符增加了很多混乱的代码。控制整个代码文件访问的最好的办法就是使用F#的签名文件,它的扩展名是.fsi,允许你指定一个完整的代码文件签名,并且签名文件的文件名称跟F#的代码文件名称是一样的。任何方法、属性在代码文件中,但是不在签名文件中的访问修饰符都是private的。这提供了一种简单方法来批量控制你的代码的访问。

下面显示了一个代码文件以及相应的签名文件,签名文件定义了一个类的构造函数和两个方法,在相应的代码文件中还有额外的属性和方法。并且就算在代码文件中这些属性和方法没有被标记为private,但是编译后的访问修饰都是private的。如果没有签名文件,那么代码文件的成员都是public的。同时还需要注意的是,如果代码文件中的成员的访问级别低于签名文件的访问级别,那么将会抛出一个异常:

 

//MyClass.fsi

namespace MyProject.Utilities
type internal MyClass =
    new : unit -> MyClass
    member public Property1 : int
    member private Method1 : int * int -> int

 

//MyClass.fs

namespace MyProject.Utilities
type internal MyClass() =
    member this.Property1 = 10
    member this.Property2 with set (x : int) = ()
    member this.Method1 (x, y) = x + y
    member this.Method2 () = true

 

原创粉丝点击