Обычно, когда код имеет много очень похожих структур, это говорит о том, что, возможно, композиция является альтернативой.
В качестве примера, предположим, что у нас есть библиотека цветных геометрических фигур с большим количествомразличных структур:
const Point = Tuple{Float64, Float64}
struct Disc
center::Point
radius::Float64
red::Float64
green::Float64
blue::Float64
end
struct Rectangle
topleft::Point
bottomright::Point
red::Float64
green::Float64
blue::Float64
end
# ... etc., e.g. Triangle, Hexagon
Теперь предположим, что мы хотим ввести функцию luminance()
, которая возвращает воспринимаемую яркость цвета формы. Одним из способов является определение метода для каждой структуры, но поскольку методы все одинаковые, мы также можем сделать:
const Shape = Union{Disc, Rectangle, Triangle, Hexagon}
luminance(shape::Shape) = 0.299*shape.red + 0.587*shape.green + 0.114*shape.blue)
Это все еще немного раздражает, потому что нам нужно, чтобы все фигуры были доступны водно место, чтобы перечислить их. Добавление новых форм будет хлопот. Таким образом, действительно, мы можем сделать abstract type Shape end
и иметь каждый подтип формы, как предложено в принятом ответе. Но во многих отношениях этот подход все еще неудовлетворителен, потому что он ограничивает все будущие Shape
s для совместного использования одного и того же макета!
Лучший способ подойти к этой проблеме - отделить red
, green
и blue
свойства, общие для всех цветных фигур. Таким образом, мы вводим иерархию типов следующим образом:
const Point = Tuple{Float64, Float64}
struct Color
red::Float64
green::Float64
blue::Float64
end
abstract type Figure end
struct Disc <: Figure
center::Point
radius::Float64
end
struct Rectangle <: Figure
topleft::Point
bottomright::Point
end
struct ColoredShape{F <: Figure}
figure::F
color::Color
end
Теперь вместо использования Rectangle((0.0, 0.0), (1.0, 1.0), 0.5, 0.5, 0.5)
для представления серого прямоугольника мы будем использовать ColoredShape(Rectange((0.0, 0.0), (1.0, 1.0)), Color(0.5, 0.5, 0.5))
. Вместо определения нескольких идентичных luminance
методов, мы бы определили его только один раз для структуры Color
. (При желании можно также определить другой метод для ColoredShape
, который делегирует свойству color
, но это только один дополнительный метод вместо N
!). Этот шаблон также позволяет повторно использовать функциональность, которую мы определяем для цветовв других контекстах, кроме цветных форм.
В целом, предпочтительнее разбивать понятия на мельчайшие усваиваемые кусочки для повторного использования и понятности. Если существует множество очень похожих структур, таких, что определение функций для всех из них кажется рутинным делом, это может означать, что может быть какая-то общая функциональность, чтобы выделить ее.