OOP In Non-OOP Languages
 

与流行的信仰相反,面向对象编程不需要OO语言。

使用OO语言获得的是一套内置的构造,可帮助您编写OO程序,但在许多情况下,它们是不必要的,有时它们会适得其反。

无论如何,这不是对OO语言的愤怒,而是反对毫无疑问地接受一种特定的OO语言来编写面向对象程序的想法。

为了证明没有必要有一个OO语言,这个例子提出了一种通常被表示为基于类的程序的例子的技术;所以这是例子,但是你不会在这个例子中找到单词类。

代码使用FB 0.16 for win32进行了测试。

如果您必须连接大多数基础知识中的很多字符串,通常会发现这是一个耗时的过程。实际上,FreeBasic字符串操作非常快,但是您仍然可以使用字符串构建器来做得更好。

字符串构建器只是一个类,它以这样的方式维护字符串缓冲区,以避免重复调用内存赋值功能,因为这是一个比较昂贵的操作。该类的方法提供了操作缓冲区并在其与本地字符串类型之间进行转换的方法。

使其比大型字符串和大量追加的内置类型更快的技巧是,该字符串保存在总是大于字符串实际长度的堆赋值缓冲区中。这意味着附加到字符串的末尾通常只是意味着将新字符串的内容复制到当前字符串的最后一个字符之后的内存位置。在这个实现中,缓冲区是一个ZString,所以很容易把它转换成一个普通的动态字符串。

FreeBasic模块封装了struct的类型定义。此结构体的实例保存对象的属性。这些方法只是在同一个模块中定义的普通FreeBasic公共函数和子句。当你想调用一个方法时,你使用正常的FreeBasic语法:
 s = StringB_ToString(AStringBInstance)


按照惯例,所有方法名称以类的名称和下划线开头,第一个参数始终是类型的实例。应始终通过引用传递此参数,以确保对状态的更改是永久性的,并且还可以避免不必要的,耗时的复制。

要添加一个新方法,只需添加一个新的函数或子跟随这些规则。

您可以轻松地实现对象的组合,但通常期望的方式继承不能完成。您可以通过在其他地方定义新的函数来引用类类型的参数来简单地扩展类。如果原始类将所有方法定义为重载,您甚至可以创建具有相同名称的新方法,只要它们具有不同的签名即可。


以下是示例代码:
'-----------------------------------------------------------------------------
' Classes without built in oop.

' Define a struct for the properties and a sub or function for each
' method.  Pass the struct as the first argument in all calls.

' By convention the argument will be Me as in VB Classic

' Strings in FB are so fast that a string builder class is 
' not needed most of the time but if you are concatenating 
' thousands of strings to build web pages for instance this might be useful.

' And please don't start complaining about the lack of inheritance; that
' is not a requirement for the use of objects.  There is no legal definition of 
' Object Oriented Programming but the most important part of any definition 
' is the close association between the data and the code that manipulates it.

'You can easily extend this class to provide more methods.
'-----------------------------------------------------------------------------


Type StringB
  Len As Integer ' used length
  allocated As Integer
  s As ZString Ptr   ' buffer of at least len characters
End Type


'-----------------------------------------------------------------------------
' Create a new StringB by calling one of these constructors.
'-----------------------------------------------------------------------------
Public Function StringB_New Overload (ByVal InitialSize As Integer) As StringB
  Dim sb As StringB
  sb.allocated = InitialSize
  sb.s = Allocate(InitialSize)
  *sb.s = ""
  StringB_New = sb
End Function


Public Function StringB_New(ByRef InitialValue As String) As StringB
  Dim sb As StringB
  sb = StringB_New(Len(InitialValue))
  *sb.s = InitialValue
  sb.len = Len(InitialValue)
  StringB_New = sb
End Function

Public Sub StringB_Dispose(ByRef Me As StringB)
  Deallocate Me.s
End Sub

  
Public Function StringB_ToString(ByRef Me As StringB) As String 
  StringB_ToString = *Me.s
End Function


Sub StringB_Append Overload(ByRef Me As StringB, ByRef s As String)

  Dim i As Integer = Me.len
  Me.len += Len(s)
  If Me.len >= Me.allocated Then
    Me.allocated = 2*Me.len
    Dim As ZString Ptr p = Reallocate(Me.s, Me.allocated )
    If p=0 Then
      ' failed to reallocate
      Print "StringB_Append failed to reallocate", Me.allocated
      Return 
    End If
    Me.s = p
  End If
  *(Me.s + i) = s
  
End Sub


Sub StringB_Append(ByRef Me As StringB, ByRef other As StringB)
  StringB_Append Me, StringB_ToString(other)
End Sub