Nieruchomość (oprogramowanie) - Property (programming)
Nieruchomość , w niektórych obiektowych języków programowania , to specjalny rodzaj klasy członka, średnio w funkcjonalności pomiędzy pola (lub członka danych) i metody . Składnia odczytywania i zapisywania właściwości jest podobna do pól, ale odczyty i zapisy właściwości są (zazwyczaj) tłumaczone na wywołania metod pobierających i ustawiających . Składnia podobna do pól jest łatwiejsza do odczytania i zapisania niż wiele wywołań metod, jednak wstawienie wywołań metod „pod maską” pozwala na walidację danych , aktywną aktualizację (np. elementów GUI ) lub implementację tego, co można nazwać „ pola tylko do odczytu ".
Zobacz pouczający przykład dla języka C# poniżej.
Wsparcie w językach
Języki programowania obsługujące właściwości obejmują ActionScript 3 , C# , D , Delphi / Free Pascal , eC , F# , Kotlin , JavaScript , Objective-C 2.0 , Python , Scala , Swift , Lua i Visual Basic .
Niektóre języki obiektowe, takie jak Java i C ++ , nie obsługują właściwości i wymagają programista zdefiniować parę dostępowych i mutator metod zamiast.
Oberon-2 zapewnia alternatywny mechanizm wykorzystujący flagi widoczności obiektów.
Inne języki zaprojektowane dla wirtualnej maszyny Java , takie jak Groovy , natywnie obsługują właściwości.
Chociaż C++ nie ma właściwości pierwszej klasy, można je emulować z powodu przeciążenia operatora .
Należy również zauważyć, że niektóre kompilatory C++ obsługują właściwości pierwszej klasy (na przykład kompilator Microsoft C++).
W większości języków właściwości są implementowane jako para metod akcesora/mutatora, ale są dostępne przy użyciu tej samej składni, co w przypadku pól publicznych. Pominięcie metody z pary daje właściwość tylko do odczytu lub rzadko spotykaną właściwość tylko do zapisu .
W niektórych językach bez wbudowanej obsługi właściwości podobną konstrukcję można zaimplementować jako pojedynczą metodę, która zwraca lub zmienia dane bazowe, w zależności od kontekstu wywołania. Takie techniki są używane np. w Perlu .
Niektóre języki (Ruby, Smalltalk) osiągają składnię podobną do właściwości przy użyciu normalnych metod, czasami z ograniczoną ilością cukru składniowego .
Warianty składni
Niektóre języki stosują dobrze ustalone konwencje składni dotyczące formalnego określania i wykorzystywania właściwości i metod.
Wśród tych konwencji:
- Notacja kropkowa
- Notacja nawiasowa
Notacja kropkowa
Poniższy przykład demonstruje notację kropkową w JavaScript.
document.createElement('pre');
Notacja nawiasowa
Poniższy przykład ilustruje notację nawiasów w JavaScript.
document['createElement']('pre');
Przykładowa składnia
C#
class Pen
{
private int color; // private field
// public property
public int Color
{
get
{
return this.color;
}
set
{
if (value > 0) {
this.color = value;
}
}
}
}
// accessing:
Pen pen = new Pen();
int color_tmp = 0;
// ...
pen.Color = 17;
color_tmp = pen.Color;
// ...
pen.Color = ~pen.Color; // bitwise complement ...
// another silly example:
pen.Color += 1; // a lot clearer than "pen.set_Color(pen.get_Color() + 1)"!
Najnowsze wersje C# umożliwiają również "właściwości implementowane automatycznie", w których pole zapasowe właściwości jest generowane przez kompilator podczas kompilacji. Oznacza to, że nieruchomość musi mieć ustawiacz. Może być jednak prywatny.
class Shape
{
public Int32 Height { get; set; }
public Int32 Width { get; private set; }
}
C++
C++ nie posiada właściwości pierwszej klasy, ale istnieje kilka sposobów na emulację właściwości w ograniczonym stopniu. Dwa z nich są następujące:
#include <iostream>
template <typename T> class property {
T value;
public:
T & operator = (const T &i) {
return value = i;
}
// This template class member function template serves the purpose to make
// typing more strict. Assignment to this is only possible with exact identical types.
// The reason why it will cause an error is temporary variable created while implicit type conversion in reference initialization.
template <typename T2> T2 & operator = (const T2 &i) {
T2 &guard = value;
throw guard; // Never reached.
}
// Implicit conversion back to T.
operator T const & () const {
return value;
}
};
struct Foo {
// Properties using unnamed classes.
class {
int value;
public:
int & operator = (const int &i) { return value = i; }
operator int () const { return value; }
} alpha;
class {
float value;
public:
float & operator = (const float &f) { return value = f; }
operator float () const { return value; }
} bravo;
};
struct Bar {
// Using the property<>-template.
property <bool> alpha;
property <unsigned int> bravo;
};
int main () {
Foo foo;
foo.alpha = 5;
foo.bravo = 5.132f;
Bar bar;
bar.alpha = true;
bar.bravo = true; // This line will yield a compile time error
// due to the guard template member function.
::std::cout << foo.alpha << ", "
<< foo.bravo << ", "
<< bar.alpha << ", "
<< bar.bravo
<< ::std::endl;
return 0;
}
Specyficzne dla C++, Microsoft i C++Builder
Przykład zaczerpnięty ze strony dokumentacji MSDN .
// declspec_property.cpp
struct S
{
int i;
void putprop(int j)
{
i = j;
}
int getprop()
{
return i;
}
__declspec(property(get = getprop, put = putprop)) int the_prop;
};
int main()
{
S s;
s.the_prop = 5;
return s.the_prop;
}
D
class Pen
{
private int m_color; // private field
// public get property
public int color () {
return m_color;
}
// public set property
public void color (int value) {
m_color = value;
}
}
auto pen = new Pen;
pen.color = ~pen.color; // bitwise complement
// the set property can also be used in expressions, just like regular assignment
int theColor = (pen.color = 0xFF0000);
W wersji D 2 każdy akcesor lub mutator właściwości musi być oznaczony @property:
class Pen
{
private int m_color; // private field
// public get property
@property public int color () {
return m_color;
}
// public set property
@property public void color (int value) {
m_color = value;
}
}
Delphi/Free Pascal
type TPen = class
private
FColor: TColor;
function GetColor: TColor;
procedure SetColor(const AValue: TColor);
public
property Color: Integer read GetColor write SetColor;
end;
function TPen.GetColor: TColor;
begin
Result := FColor;
end;
procedure TPen.SetColor(const AValue: TColor);
begin
if FColor <> AValue
then FColor := AValue;
end;
// accessing:
var Pen: TPen;
// ...
Pen.Color := not Pen.Color;
(*
Delphi also supports a 'direct field' syntax -
property Color: TColor read FColor write SetColor;
or
property Color: TColor read GetColor write FColor;
where the compiler generates the exact same code as for reading and writing
a field. This offers the efficiency of a field, with the safety of a property.
(You can't get a pointer to the property, and you can always replace the member
access with a method call.)
*)
eK
class Pen
{
// private data member
Color color;
public:
// public property
property Color color
{
get { return color; }
set { color = value; }
}
}
Pen blackPen { color = black };
Pen whitePen { color = white };
Pen pen3 { color = { 30, 80, 120 } };
Pen pen4 { color = ColorHSV { 90, 20, 40 } };
F#
type Pen() = class
let mutable _color = 0
member this.Color
with get() = _color
and set value = _color <- value
end
let pen = new Pen()
pen.Color <- ~~~pen.Color
JavaScript
function Pen() {
this._color = 0;
}
// Add the property to the Pen type itself, can also
// be set on the instance individually
Object.defineProperties(Pen.prototype, {
color: {
get: function () {
return this._color;
},
set: function (value) {
this._color = value;
}
}
});
var pen = new Pen();
pen.color = ~pen.color; // bitwise complement
pen.color += 1; // Add one
ActionScript 3.0
package {
public class Pen {
private var _color:uint = 0;
public function get color():uint {
return _color;
}
public function set color(value:uint):void {
_color = value;
}
}
}
var pen:Pen = new Pen();
pen.color = ~pen.color; // bitwise complement
pen.color += 1; // add one
Cel-C 2.0
@interface Pen : NSObject
@property (copy) NSColor *colour; // The "copy" attribute causes the object's copy to be
// retained, instead of the original.
@end
@implementation Pen
@synthesize colour; // Compiler directive to synthesise accessor methods.
// It can be left behind in Xcode 4.5 and later.
@end
Powyższy przykład może być użyty w dowolnej metodzie takiej jak ta:
Pen *pen = [[Pen alloc] init];
pen.colour = [NSColor blackColor];
float red = pen.colour.redComponent;
[pen.colour drawSwatchInRect: NSMakeRect(0, 0, 100, 100)];
PHP
class Pen
{
private int $color = 1;
function __set($property, $value)
{
if (property_exists($this, $property)) {
$this->$property = $value;
}
}
function __get($property)
{
if (property_exists($this, $property)) {
return $this->$property;
}
return null;
}
}
$p = new Pen();
$p->color = ~$p->color; // Bitwise complement
echo $p->color;
Pyton
Właściwości działają poprawnie tylko dla klas w nowym stylu (klas, które mają object
jako nadklasę ) i są dostępne tylko w Pythonie 2.2 i nowszych (zobacz odpowiednią sekcję samouczka Ujednolicenie typów i klas w Pythonie 2.2 ). Python 2.6 dodał nową składnię obejmującą dekoratory do definiowania właściwości.
class Pen:
def __init__(self) -> None:
self._color = 0 # "private" variable
@property
def color(self):
return self._color
@color.setter
def color(self, color):
self._color = color
pen = Pen()
# Accessing:
pen.color = ~pen.color # Bitwise complement ...
Rubin
class Pen
def initialize
@color = 0
end
# Defines a getter for the @color field
def color
@color
end
# Defines a setter for the @color field
def color=(value)
@color = value
end
end
pen = Pen.new
pen.color = ~pen.color # Bitwise complement
Ruby zapewnia również automatyczne syntezatory pobierające/ustawiające zdefiniowane jako metody instancji klasy.
class Pen
attr_reader :brand # Generates a getter for @brand (Read-Only)
attr_writer :size # Generates a setter for @size (Write-Only)
attr_accessor :color # Generates both a getter and setter for @color (Read/Write)
def initialize
@color = 0 # Within the object, we can access the instance variable directly
@brand = "Penbrand"
@size = 0.7 # But we could also use the setter method defined by the attr_accessor Class instance method
end
end
pen = Pen.new
puts pen.brand # Accesses the pen brand through the generated getter
pen.size = 0.5 # Updates the size field of the pen through the generated setter
pen.color = ~pen.color
Visual Basic
Visual Basic (.NET 2003-2010)
Public Class Pen
Private _color As Integer ' Private field
Public Property Color() As Integer ' Public property
Get
Return _color
End Get
Set(ByVal value As Integer)
_color = value
End Set
End Property
End Class
' Create Pen class instance
Dim pen As New Pen()
' Set value
pen.Color = 1
' Get value
Dim color As Int32 = pen.Color
Visual Basic (tylko .NET 2010)
Public Class Pen
Public Property Color() As Integer ' Public property
End Class
' Create Pen class instance
Dim pen As New Pen()
' Set value
pen.Color = 1
' Get value
Dim color As Int32 = pen.Color
Visual Basic 6
' in a class named clsPen
Private m_Color As Long
Public Property Get Color() As Long
Color = m_Color
End Property
Public Property Let Color(ByVal RHS As Long)
m_Color = RHS
End Property
' accessing:
Dim pen As New clsPen
' ...
pen.Color = Not pen.Color