ООП в не-ООП языках
 

Несмотря на популярный миф объектно-ориентированного программирования, для этого не обязательно требуется язык ООП.

ООП язык представляет собой набор встроенных конструкций, которые помогут вам в ООП написании программ, но во многих случаях они не нужны, а иногда они контрпродуктивны.

Во всяком случае, это не громкие слова против ООП языков, а громкие слова против беспрекословного принятия идеи, что нужен специальный ООП язык для написания объектно-ориентированных программ.

Для того чтобы продемонстрировать, что не обязательно иметь ООП язык, этот пример представляет метод, который обычно приводится как пример класса; но вы не найдете слово класс в этом примере.

Код был протестирован на FB 0.16 для win32.

Объединение строк в большинстве Basic процесс трудоемкий. На самом деле в FreeBASIC операции со строками выполняются удивительно быстро, но вы можете сделать еще лучше, используя конструктор строк.

Конструктор строк - это просто класс, который поддерживает строковый буфер таким образом, чтобы избежать повторных вызовов функций выделения памяти, потому что это относительно дорогая операция. Методы этого класса предоставляют способы управления буферами и преобразования между ними в собственный тип строки.

Хитрость, которая делает его быстрее, чем встроенный тип для больших строк состоит в том, что строка передается в кучу выделенного буфера, который всегда больше, чем фактическая длина строки. Это означает, что добавление в конец строки - это просто обычное копирование содержимого новой строки в ячейки памяти после последнего символа текущей строки. В этой реализации буфер ZString легко преобразовывается в обычную динамическую строку.

FreeBasic модуль инкапсулирует определение типа структуры. Экземпляры этой структуры занимают атрибуты объекта. Методы - это просто нормальные FreeBasic функции и подпрограммы, в том же модуле. Когда вы хотите вызвать метод, то используйте обычный FreeBasic синтаксис:

 s = StringB_ToString(AStringBInstance)


По соглашению имена всех методов начинаются с имени класса и подчеркивания и первый аргумент всегда является экземпляром типа. Этот аргумент всегда должен передаваться по ссылке для обеспечения постоянного изменения состояния, а также для избежания ненужного, длительного копирования.

Для добавления нового метода вы просто можете добавить новые функции или процедуры.

Вы можете легко осуществить состав объектов, но наследование не может быть сделано. Можно расширить классы просто путем определения новых функций, которые принимают аргументы типа класса. Исходный класс определяет все его методы как перегруженные. Вы можно даже создавать новые методы с тем же именем при условии, что они имеют разные сигнатуры.


Вот пример кода:
'-----------------------------------------------------------------------------
' Классы без встроенного ООП.

' Определение структуры для свойств и процедуры или функции для каждого
' метода.  Передача структуры в качестве первого аргумента во всех вызовах.


' Конвенция аргументов будет как в классическом VB

' Строки в FB настолько быстры, что класс конструктора строк
' в большинстве своем не нужен, но если вы соединяете
' тысячи строк например для создания веб-страниц
' то это может стать полезным.


' И пожалуйста не нужно жаловаться на отсутствие наследования; это
' не является требованием для использования объектов.
' ООП существует без юридического определения понятия
' "Объектно-ориентированное программирование", однако
' наиболее важной частью любого определения является
' тесная связь между данными и кодом, который управляет этими данными.


'Вы легко можете расширить этот класс, предоставив больше методов.
'-----------------------------------------------------------------------------


Type StringB
  Len As Integer ' используемая длина
  allocated As Integer
  s As ZString Ptr   ' буфер по крайней мере с Len символов
End Type


'-----------------------------------------------------------------------------
' Создание новой StringB путем вызова одного из этих конструкторов.
'-----------------------------------------------------------------------------
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