뮤테이터 메소드

컴퓨터 과학에서 **뮤테이터 메소드**(mutator method)는 변수의 변경을 통제하기 위해 사용하는 메소드이다. **세터**(setter) 메소드로 널리 알려져 있다. 프라이빗 멤버 변수의 값을 반환하는 **액세서**(accessor)로도 불리는 게터(getter)와 동반하여 자주 사용된다.

뮤테이터 메소드는 캡슐화의 원칙을 유지하면서 객체 지향 프로그래밍에 주로 사용된다. 이 원칙에 따라 클래스의 멤버 변수는 다른 코드로부터 숨겨져서 비공개되고 보호되며 원하는 새로운 값을 변수로 취하고 선택적으로 유효성을 확인하며 프라이빗 멤버 변수를 수정하는 퍼블릭 멤버 함수(뮤테이터 메소드)에 의해서만 수정이 가능하다. 뮤테이터 메소드는 할당 연산자 오버로딩과 비교되지만 이것들은 객체 계층의 레벨에서 차이가 있다.

뮤테이터 메소드는 객체 지향이 아닌 환경에서도 사용할 수 있다. 이 경우 수정할 변수의 참조는 새로운 값과 함께 뮤테이터로 전달된다. 이 시나리오에서 컴파일러는 코드가 뮤테이터 메소드를 통과하여 변수를 직접 변경하는 일에 제한을 둘 수 없다. 이 제한을 두는 책임은 개발자에게 있으며 변수가 오직 뮤테이터 메소드를 통해서만 수정이 되고 직접 수정해서는 안 되도록 보장해야 한다.

뮤테이터 메소드를 지원하는 프로그래밍 언어에서 프로퍼티는 캡슐화 활용을 포기하지 않고도 편리한 대안을 제공한다.

## 예시
### 어셈블리어

```nasm
student                   struct
    age         dd        ?
student                   ends
```


```nasm
.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
```

### C
파일 student.h:

```c
#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:

```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:

```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:

```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:

```cpp
#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:

```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 샤프:

```csharp
public class Student
{
    private string name;

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


나중 버전의 C# (.NET Framework 3.5 이상):

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



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


### 커먼 리스프

```lisp
(defclass student ()
  ((name      :initarg :name      :initform "" :accessor student-name) ; student-name is setf'able
   (birthdate :initarg :birthdate :initform 0  :reader student-birthdate)
   (number    :initarg :number    :initform 0  :reader student-number :writer set-student-number)))

;; Example of a calculated property getter (this is simply a method)
(defmethod student-age ((self student))
  (- (get-universal-time) (student-birthdate self)))

;; Example of direct slot access within a calculated property setter
(defmethod (setf student-age) (new-age (self student))
  (with-slots (birthdate) self
    (setf birthdate (- (get-universal-time) new-age))
    new-age))

;; The slot accessing options generate methods, thus allowing further method definitions
(defmethod set-student-number :before (new-number (self student))
  ;; You could also check if a student with the new-number already exists.
  (check-type new-number (integer 1 *)))
```

### D

```d
class Student {
    private char[] name_;
    // Getter
    @property char[] name() {
        return this.name_;
    }
    // Setter
    @property char[] name(char[] name_in) {
        return this.name_ = name_in;
    }
}
```


`Student` 인스턴스는 아래와 같이 사용이 가능하다:

```d
auto student = new Student;
student.name = "David";           // same effect as student.name("David")
auto student_name = student.name; // same effect as student.name()
```


### 델파이

```delphi
interface

type
  TStudent = class
  strict private
    FName: string;
    procedure SetName(const Value: string);
  public
    /// <summary>
    /// Get or set the name of the student.
    /// </summary>
    property Name: string read FName write SetName;
  end;

// ...

implementation

procedure TStudent.SetName(const Value: string);
begin
  FName := Value;
end;

end.
```

### 자바

```java
public class Student {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String newName) {
        name = newName;
    }
}
```

### 자바스크립트

```javascript
function Student(name) {
  var _name = name;

  this.getName = function() {
    return _name;
  };

  this.setName = function(value) {
    _name = value;
  };
}
```



```javascript
function Student(name){
    var _name = name;

    this.__defineGetter__('name', function() {
        return _name;
    });

    this.__defineSetter__('name', function(value) {
        _name = value;
    });
}
```



```javascript
function Student(name){
    this._name = name;
}

Student.prototype = {
    get name() {
        return this._name;
    },
    set name(value) {
        this._name = value;
    }
};
```



```javascript
var Student = {
    get name() {
        return this._name;
    },
    set name(value) {
        this._name = value;
    }
};
```



```javascript
function Student(name){
    this._name = name;
}
Object.defineProperty(Student.prototype, 'name', {
    get: function() {
        return this._name;
    },
    set: function(value) {
        this._name = value;
    }
});
```


### 액션스크립트 3.0

```actionscript
package
{
    public class Student
    {
        private var _name : String;

        public function get name() : String
        {
            return _name;
        }

        public function set name(value : String) : void
        {
            _name = value;
        }
    }
}
```


### 오브젝티브C
전통적인 Objective-C 1.0 문법 사용:

```objc
@interface Student : NSObject
{
    NSString *_name;
}

- (NSString *)name;
- (void)setName:(NSString *)name;

@end

@implementation Student

- (NSString *)name
{
    return _name;
}

- (void)setName:(NSString *)name
{
    [_name release];
    _name = [name retain];
}

@end
```


Mac OS X 10.6, iOS 4, Xcode 3.2에 사용되는 더 새로운 Objective-C 2.0 문법을 사용하여 위에 기술된 코드와 동일한 코드를 아래와 같이 생성할 수 있다:

```objc
@interface Student : NSObject

@property (nonatomic, retain) NSString *name;

@end

@implementation Student

@synthesize name = _name;

@end
```


OS X 10.8과 iOS 6를 기점으로 Xcode 4.4 이상을 사용 시 문법을 단순화할 수 있다:

```objc
@interface Student : NSObject

@property (nonatomic, strong) NSString *name;

@end

@implementation Student

//Nothing goes here and it's OK.

@end
```


### 펄

```perl
package Student;

sub new {
    bless {}, shift;
}

sub set_name {
    my $self = shift;
    $self->{name} = $_[0];
}

sub get_name {
    my $self = shift;
    return $self->{name};
}

1;
```



```perl
package Student;
use base qw(Class::Accessor);
__PACKAGE__->follow_best_practice;

Student->mk_accessors(qw(name));

1;
```



```perl
package Student;
use Moose;

# Moose uses the attribute name as the setter and getter, the reader and writer properties
# allow us to override that and provide our own names, in this case get_name and set_name
has 'name' => (is => 'rw', isa => 'Str', reader => 'get_name', writer => 'set_name');

1;
```

### PHP

```php
class Student
{
    private string $name;

    /**
     * @return string The name.
     */
    public function getName(): string
    {
        return $this->name;
    }

    /**
     * @param string $newName The name to set.
     */
    public function setName(string $newName): void
    {
        $this->name = $newName;
    }
}
```


```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
```


```pycon
>>> bob = Student("Bob")
>>> bob.name
Bob
>>> bob.name = "Alice"
>>> bob.name
Alice
>>> bob._name = "Charlie" # bypass the setter
>>> bob._name # bypass the getter
Charlie
```

### 래킷

```racket
#lang racket
(define student%
  (class object%
    (init-field name)
    (define/public (get-name) name)
    (define/public (set-name! new-name) (set! name new-name))
    (super-new)))

(define s (new student% [name "Alice"]))
(send s get-name)                       ; => "Alice"
(send s set-name! "Bob")
(send s get-name)                       ; => "Bob"
```



```racket
#lang racket
(struct student (name) #:mutable)
(define s (student "Alice"))
(set-student-name! s "Bob")
(student-name s)                        ; => "Bob"
```


### 루비
개개의 액세서와 뮤테이터 메소드를 정의하면 데이터의 전처리 또는 유효성 확인을 위한 공간을 만들어준다.

```ruby
class Student
  def name
    @name
  end

  def name=(value)
    @name=value
  end
end
```


`@name` 변수의 읽기 전용 단순 공개 접근:

```ruby
class Student
  attr_reader :name
end
```


`@name` 변수의 읽기-쓰기 단순 공개 접근:

```ruby
class Student
  attr_accessor :name
end
```


### 러스트

```rust
struct Student {
    name: String,
}

impl Student {
    fn name(&self) -> &String {
        &self.name
    }

    fn set_name(&mut self, name: String) {
        self.name = name
    }
}
```


### 스몰토크

```smalltalk
age: aNumber
     " Set the receiver age to be aNumber if is greater than 0 and less than 150 "
    (aNumber between: 0 and: 150)
       ifTrue: [ age := aNumber ]
```


### 비주얼 베이직 닷넷
기본 코드:

```vb
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 코드:

```vb
Public Class Student
    Public Property name As String
End Class
```


## 같이 보기
* 프로퍼티 (프로그래밍)
* 인덱서 (프로그래밍)
* 불변객체

분류:메소드 (컴퓨터 프로그래밍)