变异子与访问子 - 维基百科,自由的百科全书

计算机科学中变异子方法(mutator或setter)是一种用于控制变量更改的方法。通常,变异子伴随着访问子 (accessor或getter)返回私有成员变量的值。

变异子方法最常用于面向对象的编程封装,与封装原则保持一致。根据这个原则,成员变量被设为私有以隐藏和保护它们不受其他代码的影响,并且只能由公共成员函数(变异子方法)修改,该函数将所需的新值作为参数來修改私有成员变量。可以将变异子方法与赋值运算符重载进行比较。

变异子方法也可以在非面向对象的环境中使用。在这种情况下,对要修改的变量的引用与新值一起传递给变异子。编译器无法限制代码绕过变异子方法并直接更改变量。开发人员有责任确保仅通过变异子方法修改变量,而不是直接修改变量。

在支持它们的编程语言中,属性提供了一种方便的替代方案,而不放弃封装的效用。

在下面的示例中,完全实现的 变异子方法还可以验证输入数据或采取进一步的操作,例如触发事件

影响

[编辑]

定义变异子和 访问子方法或属性块的另一种方法是为实例变量提供一些可见性,而不是私有化它或直接从对象外部访问它。可以使用修改器和访问器定义更精细的控制访问权限。例如,将一个参数设为只读,可以通过定义一个访问器而不提供修改器。两种方法的可见性可能不同:访问器通常是公开的;变异子是保护的、包私有的或内部的。

定义了变异子的有机会验证或预处理传入的数据。如果保证所有外部访问都通过变异子,则无法绕过这些步骤。例如,如果日期由单独的私有 yearmonthday变量表示,则传入日期由变异子setDate 拆分,同时为了一致性,相同的私有实例变量由setYearsetMonth访问。在所有情况下,1 - 12 之外的月份值都可以被相同的代码拒绝。

相反,访问器允许从内部变量合成有用的数据表示,同时保持它们的结构封装和对外部模块不可见。货币getAmount访问子可以由一个内部私有的数值变量构建一个字符串,其小数位数由参数currency定义。

现代编程语言常提供在一行中修改器和访问器的生成样板—例如 C# 的 public string Name { get; set; }和Ruby的 attr_accessor :name 。在这些情况下,不会为验证、预处理或合成等操作创建代码块。这些简化的访问器仍然保留了对简单公共实例变量进行封装的优势,但常见的是,随着敏捷软件开发軟體維護和需求的变化,对数据的需求变得更加复杂。许多自动修改器和访问器最终会被单独的代码块取代。在实现的早期自动创建它们的好处是,无论是否添加了更复杂的类,类的公共接口都保持相同,如果添加,则不需要进行大量重构。 [1]

由于涉及额外的步骤,访问器函数的效率可能低于直接获取或存储数据字段, [2]然而,这些函数通常是内联的,从而消除了函数调用的开销。

例子

[编辑]

汇编语言

[编辑]
student                   struct     age         dd        ? student                   ends 
                     .code student_get_age       proc      object:DWORD                       mov       ebx, object                       mov       eax, student.age[ebx]                       ret student_get_age       endp  student_set_age       proc      object:DWORD, age:DWORD                       mov       ebx, object                       mov       eax, age                       mov       student.age[ebx], eax                       ret student_set_age       endp 

文件student.h:

#ifndef _STUDENT_H #define _STUDENT_H  struct student; /* opaque structure */ typedef struct student student;  student *student_new(int age, char *name); void student_delete(student *s);  void student_set_age(student *s, int age); int student_get_age(student *s); char *student_get_name(student *s);  #endif 

文件student.c:

#include <stdlib.h> #include <string.h> #include "student.h"  struct student {   int age;   char *name; };  student *student_new(int age, char *name) {   student *s = malloc(sizeof(student));   s->name = strdup(name);   s->age = age;   return s; }  void student_delete(student *s) {   free(s->name);   free(s); }  void student_set_age(student *s, int age) {   s->age = age; }  int student_get_age(student *s) {   return s->age; }  char *student_get_name(student *s) {   return s->name; } 

文件 main.c:

#include <stdio.h> #include "student.h"  int main(void) {   student *s = student_new(19, "Maurice");   char *name = student_get_name(s);   int old_age = student_get_age(s);   printf("%s's old age = %i\n", name, old_age);   student_set_age(s, 21);   int new_age = student_get_age(s);   printf("%s's new age = %i\n", name, new_age);   student_delete(s);   return 0; } 

文件 Makefile:

all: out.txt; cat $< out.txt: main; ./$< > $@ main: main.o student.o main.o student.o: student.h clean: ;$(RM) *.o out.txt main 

C++

[编辑]

文件Student.h:

#ifndef STUDENT_H #define STUDENT_H  #include <string>  class Student { public:     Student(const std::string& name);      const std::string& name() const;     void name(const std::string& name);  private:     std::string name_; };  #endif 

文件Student.cpp:

#include "Student.h"  Student::Student(const std::string& name) : name_(name) { }  const std::string& Student::name() const {     return name_; }  void Student::name(const std::string& name) {     name_ = name; } 

C#

[编辑]

C#支持属性编程

public class Student {     private string name;      /// <summary>     /// Gets or sets student's name     /// </summary>     public string Name {         get { return name; }         set { name = value; }     } } 

从(.NET Framework 3.5开始,可以缩写为自动属性:

public class Student {     public string Name { get; set; } } 

可以限制只有本类可以私有访问:

public class Student {     public string Name { get; private set; } } 

Python

[编辑]

下例子使用的类,与一个变量、一个访问子,一个变异子。

class Student:     # Initializer     def __init__(self, name: str) -> None:         # An instance variable to hold the student's name         self._name = name      # Getter method     @property     def name(self):         return self._name      # Setter method     @name.setter     def name(self, new_name):         self._name = new_name 
>>> bob = Student("Bob") >>> bob.name  Bob >>> bob.name = "Alice" >>> bob.name  Alice >>> bob._name = "Charlie" # bypass the setter >>> bob._name # bypass the getter Charlie 

Visual Basic.NET

[编辑]

类似于C#, 明确使用GetSet methods.

Public Class Student      Private _name As String      Public Property Name()         Get             Return _name         End Get         Set(ByVal value)             _name = value         End Set     End Property  End Class 

VB.NET 2010, 利用Auto Implemented创建一个属性而不必使用Get与Set语法。编译器自动创建一个隐变量,如_name对应于属性名name.

Public Class Student     Public Property name As String End Class 

参考文献

[编辑]
  1. ^ Stephen Fuqua. Automatic Properties in C# 3.0. 2009 [2009-10-19]. (原始内容存档于2011-05-13). 
  2. ^ Tim Lee. Run Time Efficiency of Accessor Functions. 1998-07-13 [2021-07-09]. (原始内容存档于2016-03-05).