Единый принцип доступа
Эта статья нуждается в дополнительных цитатах для проверки . ( январь 2010 г. ) |
Принцип единообразного доступа в компьютерном программировании был сформулирован Бертраном Мейером (первоначально в его книге «Объектно-ориентированное построение программного обеспечения »). В нем говорится: «Все услуги, предлагаемые модулем , должны быть доступны через единую нотацию, которая не выдает, реализуются ли они через хранилище или посредством вычислений». [1] [2] Этот принцип обычно применим к синтаксису объектно -ориентированных языков программирования . В более простой форме оно гласит, что не должно быть синтаксической разницы между работой с атрибутом , заранее вычисленным свойством или методом / запросом объекта.
В то время как большинство примеров сосредоточено на аспекте «чтения» принципа (т. е. извлечении значения), Мейер в своей ежемесячной колонке на тему «Запись» (т. е. изменение значения) этого принципа показывает, что труднее разобраться с последствиями этого принципа. языка программирования Eiffel . Официальный сайт [3]
Объяснение
[ редактировать ]Проблема, которую решает Мейер, связана с поддержкой крупных программных проектов или библиотек программного обеспечения. Иногда при разработке или сопровождении программного обеспечения после написания большого количества кода необходимо изменить класс или объект таким образом, чтобы превратить то, что было просто доступом к атрибуту, в вызов метода. Языки программирования часто используют другой синтаксис для доступа к атрибутам и вызова метода (например, object.something
против object.something()
). Изменение синтаксиса в популярных языках программирования того времени потребовало бы изменения исходного кода во всех местах, где использовался атрибут. Это может потребовать изменения исходного кода во многих разных местах в очень большом объеме исходного кода. Или, что еще хуже, если изменение произошло в библиотеке объектов, используемой сотнями клиентов, каждому из этих клиентов придется найти и изменить все места, где атрибут использовался в своем собственном коде, и перекомпилировать свои программы.
Обратный путь (от метода к простому атрибуту) на самом деле не был проблемой, поскольку всегда можно просто сохранить функцию и заставить ее просто возвращать значение атрибута.
Мейер признал необходимость для разработчиков программного обеспечения писать код таким образом, чтобы минимизировать или исключить каскадные изменения в коде, возникающие в результате изменений, которые преобразуют атрибут объекта в вызов метода или наоборот. Для этого он разработал принцип единого доступа.
Многие языки программирования не поддерживают UAP строго, но поддерживают его формы. Свойства, предоставляемые во многих языках программирования, по-другому решают проблему, которую Мейер решал с помощью своего UAP. Вместо предоставления единой унифицированной записи свойства предоставляют способ вызова метода объекта, используя ту же нотацию, которая используется для доступа к атрибутам. Отдельный синтаксис вызова метода по-прежнему доступен.
Пример UAP
[ редактировать ]Если язык использует синтаксис вызова метода, это может выглядеть примерно так.
// Assume print displays the variable passed to it, with or without parens // Set Foo's attribute 'bar' to value 5. Foo.bar(5) print Foo.bar()
При выполнении должно отображаться:
5
Будь или нет Foo.bar(5)
вызывает функцию или просто устанавливает атрибут, скрытый от вызывающего объекта.
Аналогично ли Foo.bar()
просто получает значение атрибута или вызывает функцию
для вычисления возвращаемого значения — это деталь реализации, скрытая от вызывающей стороны.
Если язык использует синтаксис атрибутов, синтаксис может выглядеть следующим образом.
Foo.bar = 5 print Foo.bar
Опять же, независимо от того, вызывается ли метод или просто присваивается значение атрибуту, скрыто. из вызывающего метода.
Проблемы
[ редактировать ]Однако UAP сам по себе может привести к проблемам, если его использовать в местах, где различия между методами доступа не являются незначительными, например, когда вычисление возвращаемого значения требует больших затрат или запускает операции кэширования. [2]
Примеры языков
[ редактировать ]Питон
[ редактировать ]Свойства Python могут использоваться для разрешения метода быть вызван с тем же синтаксисом, что и доступ к атрибуту. В то время как UAP Мейера имел бы единое обозначение как для доступа к атрибутам, так и для вызова метода (синтаксис вызова метода), язык с поддержкой свойств по-прежнему поддерживает отдельные обозначения атрибутов и доступ к методу. Свойства позволяют использовать нотацию атрибута, но скрывают тот факт, что метод вызывается, а не просто получает или устанавливает значение.
Таким образом, Python оставляет возможность соблюдения UAP на усмотрение отдельного программиста. Встроенный @property
Функция обеспечивает простой способ оформления любого данного метода в синтаксисе доступа к атрибутам, тем самым абстрагируя синтаксическую разницу между вызовами методов и доступом к атрибутам. [4]
В Python у нас может быть код, который обращается к Egg
объект, который можно определить так, что вес и цвет являются простыми атрибутами, как показано ниже.
"""
>>> egg = Egg(4.0, "white")
>>> egg.color = "green"
>>> print(egg)
Egg(4.0, green)
"""
class Egg:
def __init__(self, weight, color) -> None:
self.weight = weight
self.color = color
def __str__(self) -> str:
return f"{__class__.__name__}({self.weight}, {self.color})"
Или объект Egg может использовать свойства и вместо этого вызывать методы получения и установки.
# ...(snip)...
class Egg:
def __init__(self, weight_oz: float, color_name: float) -> None:
self.weight = weight_oz
self.color = color_name
@property
def color(self) -> str:
'''Color of the Egg'''
return to_color_str(self._color_rgb)
@color.setter
def color(self, color_name: str) -> None:
self._color_rgb = to_rgb(color_name)
@property
def weight(self) -> float:
'''Weight in Ounces'''
return self._weight_gram / 29.3
@weight.setter
def weight(self, weight_oz: float) -> None:
self._weight_gram = 29.3 * weight_oz
# ...(snip)...
Независимо от того, каким путем Egg
определен, вызывающий код может остаться прежним. Осуществление Egg
может переключаться из одной формы в другую, не затрагивая код, использующий класс Egg. Языки, реализующие UAP, также обладают этим свойством.
Руби
[ редактировать ]Рассмотрим следующее
y = Egg.new("Green")
y.color = "White"
puts y.color
Теперь класс Egg можно определить следующим образом
class Egg
attr_accessor :color
def initialize(color)
@color = color
end
end
Приведенный выше начальный сегмент кода будет отлично работать, если Egg будет определен как таковой. Яйцо Класс также можно определить, как показано ниже, где цвет — это метод. Вызывающий код будет все еще работает, без изменений, если Egg определить следующим образом.
class Egg
def initialize(color)
@rgb_color = to_rgb(color)
end
def color
to_color_name(@rgb_color)
end
def color=(color)
@rgb_color = to_rgb(color)
end
private
def to_rgb(color_name)
.....
end
def to_color_name(color)
....
end
end
Обратите внимание, что хотя color
выглядит как атрибут в одном случае и пара методов
в следующем интерфейс класса остается прежним. Человек, поддерживающий класс Egg, может переключаться с одной формы на другую, не опасаясь взлома кода вызывающего объекта.
Ruby следует за пересмотренным UAP, attr_accessor :color
действует только как синтаксический сахар для создания методов доступа/установки для color
. В Ruby нет способа получить переменную экземпляра из объекта без вызова для нее метода.
Строго говоря, Ruby не следует оригинальному UAP Мейера в том смысле, что синтаксис доступа к атрибуту отличается от синтаксиса вызова метода. Но здесь доступ к атрибуту всегда будет осуществляться через функцию, которая часто генерируется автоматически. Таким образом, по сути, любой тип доступа вызывает функцию, и язык соответствует пересмотренному принципу унифицированного доступа Мейера.
С#
[ редактировать ]Язык C# поддерживает свойства классов , которые предоставляют средства для определения get
и set
операции ( геттеры и сеттеры ) для переменной-члена. Синтаксис доступа к свойству или его изменения такой же, как и для доступа к любой другой переменной-члену класса, но фактическая реализация этого может быть определена либо как простой доступ для чтения/записи, либо как функциональный код.
public class Foo
{
private string _name;
// Property
public int Size
{
get; // Getter
set; // Setter
}
// Property
public string Name
{
get { return _name; } // Getter
set { _name = value; } // Setter
}
}
В приведенном выше примере класс Foo
содержит два свойства, Size
и Name
. Size
Свойство — это целое число, которое можно читать (получить) и записать (установить). Аналогичным образом, Name
Свойство — это строка, которую также можно читать и изменять, но ее значение хранится в отдельной (частной) переменной класса. _name
.
Опуская set
операция в определении свойства делает свойство доступным только для чтения, опуская при этом get
операция делает его доступным только для записи.
Использование свойств использует UAP, как показано в коде ниже.
public Foo CreateFoo(int size, string name)
{
var foo = new Foo();
foo.Size = size; // Property setter
foo.Name = name; // Property setter
return foo;
}
С++
[ редактировать ]В C++ нет ни UAP, ни свойств, когда объект изменяется так, что атрибут (цвет) становится парой функций ( getA, setA ). Любое место в нем использует экземпляр объекта и либо устанавливает, либо получает значение атрибута ( x = obj.color
или obj.color = x
) необходимо изменить для вызова одной из функций. ( x = obj.getColor()
или obj.setColor(x)
). Используя шаблоны и перегрузку операторов , можно подделать свойства, но это сложнее, чем в языках, которые напрямую поддерживают свойства. Это усложняет сопровождение программ на C++. Распределенные библиотеки объектов C++ должны с осторожностью относиться к тому, как они предоставляют доступ к данным-членам.
JavaScript
[ редактировать ]JavaScript поддерживает вычисляемые свойства с 2009 года. [5]
Ссылки
[ редактировать ]- ^ Мейер, Бертран (1997). Объектно-ориентированное построение программного обеспечения (второе изд.). Прентис Холл. п. 57. ИСБН 978-0-13-629155-8 .
- ^ Jump up to: а б «Принцип UniformAccess» . c2 вики . Проверено 6 августа 2013 г.
- ^ Мейер, Бертран. «Колонка EiffelWorld: Бизнес плюс удовольствие» . Проверено 6 августа 2013 г.
- ^ Официальная документация Python, встроенные функции.
- ^ w3schools.com, Средства доступа к Javascript