변이법

Mutator method

컴퓨터 과학에서 변이자 방법은 변수에 대한 변경을 제어하는 데 사용되는 방법입니다.그것들은 세터 방식으로도 널리 알려져 있습니다.대부분의 경우 세터는 개인 멤버 변수의 값을 반환하는 getter(접근자라고도 함)를 수반합니다.

변환기 방식은 캡슐화 원리에 따라 객체 지향 프로그래밍에서 가장 자주 사용됩니다.이 원리에 따르면 클래스의 멤버 변수는 다른 코드로부터 숨기거나 보호하기 위해 프라이빗하게 되며, 원하는 새로운 값을 파라미터로 하여 임의로 검증하고 프라이빗 멤버 변수를 변경하는 퍼블릭 멤버 함수(변환자 방식)에 의해서만 변경할 수 있다.뮤테이터 메서드는 할당 연산자 오버로드와 비교할 수 있지만 일반적으로 개체 계층의 다른 수준에서 나타납니다.

뮤테이터 메서드는 오브젝트 지향적이지 않은 환경에서도 사용할 수 있습니다.이 경우 변경할 변수에 대한 참조가 새 값과 함께 변환기에 전달됩니다.이 시나리오에서 컴파일러는 코드가 변환기 메서드를 바이패스하여 변수를 직접 변경하는 것을 제한할 수 없습니다.변수를 직접 수정하지 않고 변환기 방식으로만 수정할 책임은 개발자에게 있습니다.

이를 지원하는 프로그래밍 언어에서 속성은 캡슐화 유틸리티를 포기하지 않고 편리한 대안을 제공합니다.

다음 예에서는 완전히 구현된 뮤테이터 메서드를 사용하여 입력 데이터를 검증하거나 이벤트를 트리거하는 등의 추가 액션을 수행할 도 있습니다.

시사점

변환자 및 접근자 메서드 또는 속성 블록을 정의하는 대신 인스턴스 변수를 프라이빗 이외의 가시성을 제공하고 개체 외부에서 직접 액세스합니다.액세스 권한의 보다 상세한 제어는, 변이자나 액세스 업체를 사용해 정의할 수 있습니다.예를 들어 파라미터는 단순히 접근자를 정의하는 것만으로 읽기 전용으로 할 수 있지만 변환자는 정의할 수 없습니다.두 가지 방법의 가시성은 다를 수 있습니다.변환자가 보호되고 있는 동안 접근자가 공개되어 있는 경우 패키지 전용 또는 내부로 보호되어 있는 것이 도움이 되는 경우가 많습니다.

뮤테이터가 정의되어 있는 블록은, 착신 데이터의 검증 또는 전처리를 실시할 수 있는 기회를 제공합니다.모든 외부 액세스가 뮤테이터를 경유하는 것이 보증되어 있는 경우는, 이러한 순서를 바이패스 할 수 없습니다.예를 들어, 날짜가 개별 비공개로 표시되는 경우year,month그리고.day변수, 그러면 착신 날짜를 다음 순서로 분할할 수 있습니다.setDate일관성을 유지하기 위해 동일한 개인 인스턴스 변수에 액세스하는 동안 변환기setYear그리고.setMonth모든 경우 1~12 이외의 월 값은 동일한 코드로 거부될 수 있습니다.

접근자는 반대로 내부 변수에서 유용한 데이터 표현을 통합할 수 있으며, 그 구조는 캡슐화되어 외부 모듈로부터 숨겨집니다.화폐getAmountaccessor는 숫자 변수에서 숨김으로 정의된 소수 자릿수를 사용하여 문자열을 작성할 수 있습니다.currency파라미터를 지정합니다.

현대의 프로그래밍 언어에서는 많은 경우 C#의 경우와 같이 단일 회선으로 변환자 및 접근자를 위한 보일러 플레이트를 생성할 수 있습니다.public string Name { get; set; }그리고 루비의attr_accessor :name이 경우 검증, 전처리, 합성을 위한 코드 블록은 생성되지 않습니다.이러한 단순화된 접근기는 여전히 단순한 퍼블릭인스턴스 변수에 비해 캡슐화의 이점을 유지하지만 시스템 설계가 진행됨에 따라 소프트웨어유지되고 요건이 변경됨에 따라 데이터에 대한 요구가 더욱 정교해지는 것이 일반적입니다.많은 자동변환기와 접근기는 결국 별도의 코드 블록으로 대체됩니다.구현 초기에 이들을 자동으로 생성함으로써 얻을 수 있는 이점은 클래스의 퍼블릭인터페이스가 더 정교해지든 아니든 동일하게 유지된다는 것입니다.클래스의 퍼블릭인터페이스가 [1]더 정교해질 경우 광범위한 리팩터링이 필요하지 않습니다.

정의되어 있는 클래스 내부에서 변환자와 접근자를 가진 파라미터를 조작하려면 종종 추가 검토가 필요합니다.구현 초기에는 이러한 블록에 추가 코드가 거의 없거나 전혀 없는 경우 프라이빗 인스턴스 변수에 직접 액세스하든 그렇지 않든 차이가 없습니다.검증, 교차 검증, 데이터 무결성 검사, 전처리 또는 기타 정교함이 추가되면 일부 내부 액세스에서 새로운 코드를 사용하고 다른 곳에서는 코드를 바이패스하는 미묘한 오류가 발생할 수 있습니다.

액세스 함수는 추가 단계를 [2]수반하기 때문에 데이터 필드를 직접 가져오거나 저장하는 것보다 효율적이지 않을 수 있지만, 이러한 함수는 종종 인라인 처리되어 함수 호출의 오버헤드를 제거합니다.

어셈블리

학생입니다                   구조     나이         dd        ? 학생입니다                    
                     코드 student_get_age       프로세서      물건:DWORD                       움직이다       ebx, 물건                       움직이다       이액스, student.age.[ebx]                       리트 student_get_age         student_set_age       프로세서      물건:DWORD, 나이:DWORD                       움직이다       ebx, 물건                       움직이다       이액스, 나이                       움직이다       student.age.[ebx], 이액스                       리트 student_set_age        

C

파일 학생입니다.h:

#ifndef_Student_H #정의_학생_H  구조 학생입니다; /* 불투명한 구조 */ 유형화된 구조 학생입니다 학생입니다;  학생입니다 *student_new(인트 나이,  *이름.); 무효 student_delete(학생입니다 *s);  무효 student_set_age(학생입니다 *s, 인트 나이); 인트 student_get_age(학생입니다 *s);  *student_get_name(학생입니다 *s);  #엔디프 

파일 student.c:

#실패하다 <stdlib.h> #실패하다 <문자열>h> #실패하다 "그럴 수도 있어요.h"  구조 학생입니다 {   인트 나이;    *이름.; };  학생입니다 *student_new(인트 나이,  *이름.) {   학생입니다 *s = 마로크(크기(학생입니다));   s->이름. = 스트러프(이름.);   s->나이 = 나이;   돌아가다 s; }  무효 student_delete(학생입니다 *s) {   공짜(s->이름.);   공짜(s); }  무효 student_set_age(학생입니다 *s, 인트 나이) {   s->나이 = 나이; }  인트 student_get_age(학생입니다 *s) {   돌아가다 s->나이; }   *student_get_name(학생입니다 *s) {   돌아가다 s->이름.; } 

파일 main.c:

#실패하다 <stdio.h> #실패하다 "그럴 수도 있어요.h"  인트 주된(무효) {   학생입니다 *s = student_new(19, 마우리스);    *이름. = student_get_name(s);   인트 old_age = student_get_age(s);   인쇄물(%s의 노후 = %i\n", 이름., old_age);   student_set_age(s, 21);   인트 new_age = student_get_age(s);   인쇄물(%s의 새 시대 = %i\n", 이름., new_age);   student_delete(s);   돌아가다 0; } 

파일 Makefile:

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

C++

파일에 Student.h:

#ifndef #학생 정의_H  #실패하다 <문자열>  학급 학생입니다 { 일반의:     학생입니다(컨스턴트 표준::스트링& 이름.);      컨스턴트 표준::스트링& 이름.() 컨스턴트;     무효 이름.(컨스턴트 표준::스트링& 이름.);  사적인:     표준::스트링 이름_; };  #엔디프 

Student.cpp 파일의 경우:

#실패하다 "학생입니다.h"  학생입니다::학생입니다(컨스턴트 표준::스트링& 이름.) : 이름_(이름.) { }  컨스턴트 표준::스트링& 학생입니다::이름.() 컨스턴트 {     돌아가다 이름_; }  무효 학생입니다::이름.(컨스턴트 표준::스트링& 이름.) {     이름_ = 이름.; } 

C#

이 예에서는 클래스 멤버의 특수한 유형인 속성대한 C# 아이디어를 보여 줍니다.Java와 달리 명시적 메서드는 정의되지 않습니다. 퍼블릭 '속성'에는 액션을 처리하는 논리가 포함되어 있습니다.삽입(미신고) 변수 사용에 유의하십시오.value.

일반의 학급 학생입니다 {     사적인 스트링 이름.;      // </ </filters>     /// 학생 이름을 가져오거나 설정합니다.     // </filters>     일반의 스트링 이름. {         얻다 { 돌아가다 이름.; }         세트 { 이름. = 가치; }     } } 

이후 C# 버전(.NET Framework 3.5 이상)는 개인 변수를 선언하지 않고 다음과 같이 생략할 수 있습니다.name.

일반의 학급 학생입니다 {     일반의 스트링 이름. { 얻다; 세트; } } 

생략 구문을 사용하면 기본 변수를 클래스 내부에서 사용할 수 없게 됩니다.그 결과,set속성의 일부가 할당에 존재해야 합니다.에 의해 접근을 제한할 수 있습니다.set특정 액세스 수식자.

일반의 학급 학생입니다 {     일반의 스트링 이름. { 얻다; 사적인 세트; } } 

일반적인 리스프

Common Lisp Object System에서는 클래스 정의 내의 슬롯 사양에 따라:reader,:writer그리고.:accessor판독기 방법, 설정기 방법 및 접근기 방법을 정의하는 옵션(복수라도 가능)setf메서드).[3]슬롯은 항상 이름을 사용하여 직접 액세스할 수 있습니다.with-slots그리고.slot-value및 슬롯 액세스 옵션에서는, 를 사용하는 특수한 방식을 정의합니다.slot-value를 클릭합니다.[4]

MetaObject Protocol 확장은 슬롯의 리더 및 라이터 함수 이름에 액세스하는 수단을 지정하지만 CLOS 자체에는 속성의 개념이 없습니다.:accessor옵션을 선택합니다.[5]

다음 예시는 이러한 슬롯옵션과 직접 슬롯액세스를 사용한 학생 클래스의 정의를 나타내고 있습니다.

(디클래스 학생입니다 ()   ((이름.      : initarg : 이름      : 초기화 "" : 악세사리 학생명) ; student-name은 설정 가능합니다.    (생년월일 : initarg : 생년월일 : 초기화 0  : 개요 학생 생년월일)    (번호    : initarg : 번호    : 초기화 0  : 개요 학생 번호 : 라이터 set-module-number)))  ;; 계산된 속성 getter의 예(이것은 단순한 메서드입니다) (디프로덕트 학생 연령 ((자신 학생입니다))   (- (get-universal-time(범용시간)) (학생 생년월일 자신)))  ;; 계산된 속성 설정기 내의 직접 슬롯액세스의 예 (디프로덕트 (설정 학생 연령) (뉴에이지 (자신 학생입니다))   (미끄럼틀이 있는 (생년월일) 자신     (설정 생년월일 (- (get-universal-time(범용시간)) 뉴에이지))     뉴에이지))  ;;; 슬롯액세스 옵션에 의해 메서드가 생성되므로 추가 메서드 정의가 가능합니다. (디프로덕트 set-module-number : 전 (새로운 번호 (자신 학생입니다))   ;; 새로운 번호를 가진 학생이 이미 존재하는지 확인할 수도 있습니다.   (체크형 새로운 번호 (정수 1 *))) 

D

D는 getter 및 setter 함수 구문을 지원합니다.버전 2의 언어 getter 및 setter 클래스/구조 메서드에서는@property속성을 [6][7]지정합니다.

학급 학생입니다 {     사적인 [] 이름_;     // Getter(게터)     @parames(@parames) [] 이름.() {         돌아가다 이것..이름_;     }     // 설정기     @parames(@parames) [] 이름.([] name_in) {         돌아가다 이것..이름_ = name_in;     } } 

A Studentinstance는 다음과 같이 사용할 수 있습니다.

자동 학생입니다 = 신규 학생입니다; 학생입니다.이름. = "데이비드";           // student.name (David)와 같은 효과) 자동 student_name = 학생입니다.이름.; // student.name()과 같은 효과 

델파이

이것은 델파이 언어로 된 간단한 수업으로 개인 필드에 접근하기 위한 공공재산의 개념을 보여줍니다.

인터페이스  유형   TSTudent = 학급   엄격한. 사적인     FName: 스트링;     절차. Set Name(Set Name)(컨스턴트 가치: 스트링);   일반의     // </ </filters>     /// 학생의 이름을 가져오거나 설정합니다.     // </filters>     소유물 이름.: 스트링 읽어주세요 FName 쓰다 Set Name(Set Name);   끝.;  // ...  실행  절차. TSTudent.Set Name(Set Name)(컨스턴트 가치: 스트링); 시작한다.   FName := 가치; 끝.;  끝.. 

자바

이름만 저장되어 있는 학생을 나타내는 이 단순한 클래스의 예에서는 가변명이 프라이빗하다는 것을 알 수 있습니다.즉, Student 클래스에서만 볼 수 있으며, "setter"와 "getter"는 퍼블릭하다는 것을 알 수 있습니다.getName()" 및 "setName(name)" 메서드.

일반의 학급 학생입니다 {     사적인 스트링 이름.;      일반의 스트링 getName() {         돌아가다 이름.;     }          일반의 무효 setName(스트링 새 이름) {         이름. = 새 이름;     } } 

자바스크립트

이 예에서는 컨스트럭터 함수Student이름만 저장된 학생을 나타내는 객체를 만드는 데 사용됩니다.

기능. 학생입니다(이름.) {   변화하다 이름 = 이름.;    이것..getName = 기능.() {     돌아가다 이름;   };    이것..setName = 기능.(가치) {     이름 = 가치;   }; } 

또는 (Web 브라우저에서 접근자를 정의하기 위해 권장되지 않는 방법을 사용)[8]

기능. 학생입니다(이름.){     변화하다 이름 = 이름.;         이것..__defineGetter__(이름, 기능.() {         돌아가다 이름;     });         이것..__defineSetter__(이름, 기능.(가치) {         이름 = 가치;     }); } 

또는 (상속 및 ES6 액세스자 구문에 프로토타입 사용):

기능. 학생입니다(이름.){     이것..이름 = 이름.; }  학생입니다.시제품 = {     얻다 이름.() {         돌아가다 이것..이름;     },     세트 이름.(가치) {         이것..이름 = 가치;     } }; 

또는 (시제품 사용 안 함):

변화하다 학생입니다 = {     얻다 이름.() {         돌아가다 이것..이름;     },     세트 이름.(가치) {         이것..이름 = 가치;     } }; 

또는 (defineProperty 사용):

기능. 학생입니다(이름.){     이것..이름 = 이름.; } 물건.define Property(정의 속성)(학생입니다.시제품, 이름, {     얻다: 기능.() {         돌아가다 이것..이름;     },     세트: 기능.(가치) {         이것..이름 = 가치;     } }); 

액션 스크립트 3.0

패키지 {     일반의 학급 학생입니다     {         사적인 변화하다 이름 : 스트링;            일반의 기능. 얻다 이름.() : 스트링         {              돌아가다 이름;         }          일반의 기능. 세트 이름.(가치 : 스트링) : 무효         {             이름 = 가치;         }     } } 

목표-C

Ubuntu 12.04의 GNUstep에서 작동하는 것과 같이 수동 참조 카운트를 사용하여 기존 Objective-C 1.0 구문을 사용합니다.

@interface student : NSObject { NSString *_name; } - (NSString *)name; - (void)setName: (NSString *)name; @end @sentation student - (NSString *)이름 {retname; } - (void)설정명: (SSString *)

Mac OS X 10.6, iOS 4 Xcode 3.2에서 사용되는 새로운 Objective-C 2.0 구문을 사용하여 위에서 설명한 것과 동일한 코드를 생성합니다.

@interface Student : NSObject @nonatomic, retain) NSString *name; @end @communication Student @size name = _name; @end

또한 OS X 10.8 및 iOS 6부터는 Xcode 4.4 이후를 사용하면서 구문을 단순화할 수 있습니다.

@interface Student : NSObject @property (비원자성, strong) NSString *name; @end @implementation Student //아무것도 여기에 들어가지 않고 OK. @end

패키지 학생입니다;  후보선수 신규 {     축복하다 {}, 교대하다; }  후보선수 set_name {     나의 자기 부담 = 교대하다;     자기 부담->{이름.} = $_[0]; }  후보선수 get_name {     나의 자기 부담 = 교대하다;     돌아가다 자기 부담->{이름.}; }  1; 

또는 클래스 사용:악세사리

패키지 학생입니다; 사용하다 기초 qw(클래스::악세사리); __PACKAGE__->베스트 프랙티스에 따르다;  학생입니다->mk_액세서(qw(이름));  1; 

또는 무스 오브젝트 시스템을 사용하여 다음을 수행합니다.

패키지 학생입니다; 사용하다 무스;  # Moose는 속성명을 setter 및 getter, reader 및 writer 속성으로 사용합니다. # 이 경우 get_name과 set_name을 덮어쓰고 자신의 이름을 지정할 수 있습니다. 가지다 이름 => ( => 'rw', 이사 => '스트레이트', 독자 => 'get_name', 작가. => 'set_name');  1; 

PHP

PHP는 "매직 메서드"를 정의합니다.__get그리고.__set오브젝트의 [9]속성을 지정합니다.

저장된 이름만 있는 학생을 나타내는 이 단순한 클래스의 예에서는 가변 이름이 비공개인 것을 알 수 있습니다. 즉, Student 클래스에서만 볼 수 있으며 "setter"와 "getter"는 공개입니다.getName()그리고.setName('name')방법들.

학급 학생입니다 {     사적인 스트링 이름;      /** * @return string 이름 */     일반의 기능. getName(): 스트링     {         돌아가다 $ this->이름.;     }      /** * @param string $newName 설정할 이름. */     일반의 기능. setName(스트링 $newName): 무효     {         $ this->이름. = $newName;     } } 

파이썬

이 예에서는 변수, getter 및 setter가1개 있는 Python 클래스를 사용합니다.

학급 학생입니다:     이니셜라이저 수     방어하다 __init__(자신, 이름.: 스트레이트) -> 없음.:         # 학생의 이름을 유지하는 인스턴스 변수         자신.이름 = 이름.      # Getter 메서드     @parames(@parames)     방어하다 이름.(자신):         돌아가다 자신.이름      # 세터 방식     @name.세터     방어하다 이름.(자신, new_name):         자신.이름 = new_name 
>>>밥. = 학생입니다() >>>밥..이름.  밥. >>>밥..이름. = 앨리스 >>>밥..이름.  앨리스야. >>>밥..이름 = '찰리' # 세터를 바이패스합니다. >>>밥..이름 # getter를 바이패스 찰리. 

라켓

Racket에서 오브젝트 시스템은 모듈 및 유닛과 더불어 제공되는 코드를 정리하는 방법입니다.언어의 다른 부분과 마찬가지로 오브젝트 시스템은 퍼스트 클래스 값을 가지며 어휘 스코프는 오브젝트 및 메서드에 대한 접근을 제어하기 위해 사용됩니다.

#실패하다라켓 (정의하다 학생 %   (학급 오브젝트 %     (초기화 필드 이름.)     (정의/공개 (이름을 붙이다) 이름.)     (정의/공개 (셋네임! 새 이름) (세트! 이름. 새 이름))     (초신형)))  (정의하다 s (신규 학생 % [이름. 앨리스])) (보내세요 s 이름을 붙이다)                       ; => "앨리스" (보내세요 s 셋네임! ) (보내세요 s 이름을 붙이다)                       ; => "밥" 

구조 정의는 새로운 유형의 값을 정의하는 대체 방법이며, 명시적으로 필요한 경우 변이자가 존재합니다.

#실패하다라켓 (구조 학생입니다 (이름.) #: 가변) (정의하다 s (학생입니다 앨리스)) (set-module-name! s ) (학생명 s)                        ; => "밥" 

루비

루비에서는 개별 접근자 및 뮤테이터 메서드를 정의하거나 메타프로그래밍을 구성할 수 있습니다.attr_reader또는attr_accessor는 클래스 내의 개인 변수를 선언하기 위해 사용할 수도 있고 각각 읽기 전용 또는 읽기/쓰기 퍼블릭액세스를 제공하기 위해 사용할 수도 있습니다.

개별 접근자 및 뮤테이터 방식을 정의하면 데이터의 전처리 또는 검증을 위한 공간이 생깁니다.

학급 학생입니다   방어하다 이름.     @name   끝.    방어하다 이름=(가치)     @name=가치   끝. 끝. 

읽기 전용의 심플한 퍼블릭 액세스(암묵적)@name변수

학급 학생입니다   attr_filterface : 이름 끝. 

암시적 접근에 대한 간단한 읽기/쓰기@name변수

학급 학생입니다   attr_accessor : 이름 끝. 

스몰토크

 age: aNumber 0보다 크고 150보다 작은 경우 수신기의 에이징을 aNumber로 설정합니다(aNumber: 0 ~: 150). ifTrue: [ age : = aNumber ]

재빠르다

학급 학생입니다 {     사적인 변화하다 이름: 스트링 = ""      변화하다 이름.: 스트링 {         얻다 {             돌아가다 자신.이름         }         세트 {             자신.이름 = 새로운 가치         }     } } 

Visual Basic.그물

다음 예시는 VB를 나타내고 있습니다.클래스에서 사용되는 속성에 대한 NET 아이디어.C#과 마찬가지로, C#의 명시적인 사용법이 있습니다.Get그리고.Set방법들.

일반의 학급 학생입니다      사적인 이름 ~하듯이 스트링      일반의 소유물 이름.()         얻다             돌아가다 이름         끝. 얻다         세트(바이밸 가치)             이름 = 가치         끝. 세트     끝. 소유물  끝. 학급 

VB.NET 2010에서는 자동 구현 속성을 사용하여 Get 및 Set 구문을 사용하지 않고도 속성을 생성할 수 있습니다.숨겨진 변수는 컴파일러에 의해 생성됩니다._name, 속성에 대응합니다.name. 클래스 내의 다른 변수 사용_name에러가 발생합니다.기본 변수에 대한 특권 액세스는 클래스 내에서 사용할 수 있습니다.

일반의 학급 학생입니다     일반의 소유물 이름. ~하듯이 스트링 끝. 학급 

「 」를 참조해 주세요.

레퍼런스

  1. ^ Stephen Fuqua (2009). "Automatic Properties in C# 3.0". Archived from the original on 2011-05-13. Retrieved 2009-10-19.
  2. ^ Tim Lee (1998-07-13). "Run Time Efficiency of Accessor Functions".
  3. ^ "CLHS: Macro DEFCLASS". Retrieved 2011-03-29.
  4. ^ "CLHS: 7.5.2 Accessing Slots". Retrieved 2011-03-29.
  5. ^ "MOP: Slot Definitions". Retrieved 2011-03-29.
  6. ^ "Functions - D Programming Language". Retrieved 2013-01-13.{{cite web}}: CS1 maint :url-status (링크)
  7. ^ "The D Style". Retrieved 2013-02-01.
  8. ^ "Object.prototype.__defineGetter__() - JavaScript MDN". developer.mozilla.org. Retrieved 2021-07-06.
  9. ^ "PHP: Overloading - Manual". www.php.net. Retrieved 2021-07-06.