ミューテイタ法

ウィキペディアから、無料の百科事典
ナビゲーションにジャンプ 検索にジャンプ

コンピュータサイエンスではミューテイタメソッド変数への変更を制御するために使用されるメソッドです。これらは、セッターメソッドとしても広く知られています。多くの場合、セッターには、プライベートメンバー変数の値を返す ゲッター(まとめてアクセサーとも呼ばれます)が付属しています。

ミューテイタメソッドは、カプセル化の原則に従って、オブジェクト指向プログラミングで最もよく使用されます。この原則によれば、クラスのメンバー変数は、他のコードから非表示にして保護するためにプライベートにされ、必要な新しい値をパラメーターとして受け取り、オプションで検証するパブリックメンバー関数(ミューテイターメソッド)によってのみ変更できます。それ、およびプライベートメンバー変数を変更します。ミューテイタメソッドは、代入演算子のオーバーロードと比較できますが、通常、オブジェクト階層のさまざまなレベルで表示されます。

ミューテイタメソッドは、非オブジェクト指向環境でも使用できます。この場合、変更される変数への参照は、新しい値とともにミューテーターに渡されます。このシナリオでは、コンパイラーは、コードがミューテイターメソッドをバイパスして変数を直接変更することを制限できません。変数がミューテイターメソッドを介してのみ変更され、直接変更されないようにする 責任は開発者にあります。

それらをサポートするプログラミング言語では、プロパティはカプセル化のユーティリティをあきらめることなく便利な代替手段を提供します。

以下の例では、完全に実装されたミューテイターメソッドは、入力データを検証したり、イベントのトリガーなどのアクションを実行したりすることもできます。

含意

ミューテイターメソッドとアクセサーメソッド、またはプロパティブロックを定義する代わりに、インスタンス変数にプライベート以外の可視性を与え、オブジェクト外部から直接アクセスすることもできますアクセス権のより細かい制御は、ミューテーターとアクセサーを使用して定義できます。たとえば、ミューテーターではなくアクセサーを定義するだけで、パラメーターを読み取り専用にすることができます。2つの方法の可視性は異なる場合があります。ミューテーターが保護されたまま、パッケージプライベートまたは内部にある間、アクセサーがパブリックであると便利なことがよくあります。

ミューテーターが定義されているブロックは、受信データの検証または前処理の機会を提供ますすべての外部アクセスがミューテーターを介して行われることが保証されている場合、これらの手順をバイパスすることはできません。たとえば、日付が個別のプライベート変数と変数yearで表されている場合、一貫性を保つために、とによって同じプライベートインスタンス変数にアクセスしながら、着信日付をミューテーター分割できますすべての場合において、1〜12以外の月の値は同じコードで拒否できます。 monthdaysetDatesetYearsetMonth

逆に、アクセサーは、構造をカプセル化して外部モジュールから隠したまま、内部変数からの有用なデータ表現の合成を可能にします。金銭的アクセサは、非表示のパラメータ getAmountで定義された小数点以下の桁数で数値変数から文字列を作成できます。currency

最近のプログラミング言語では、C#やRubyのように、ミューテーターとアクセサーの定型文を1行で生成できることがよくあります。このような場合、検証、前処理、または合成のためのコードブロックは作成されません。これらの単純化されたアクセサーは、単純なパブリックインスタンス変数に対するカプセル化の利点を引き続き保持しますが、システム設計が進むにつれて、ソフトウェアが維持され、要件が変化するにつれて、データに対する要求が変化するのが一般的です。public string Name { get; set; }attr_accessor :nameより洗練されたものになります。多くの自動ミューテーターとアクセサーは、最終的には別々のコードブロックに置き換えられます。実装の初期段階でそれらを自動的に作成する利点は、より高度な機能が追加されているかどうかに関係なく、クラスのパブリックインターフェイスが同じままであり、追加されている場合は大規模なリファクタリングを必要としないことです。[1]

ミューテーターとアクセサーが定義されているクラス内からパラメーターを操作するには、多くの場合、追加の考慮が必要です。実装の初期の頃、これらのブロックに追加のコードがほとんどまたはまったくない場合、プライベートインスタンス変数に直接アクセスするかどうかに違いはありません。検証、相互検証データ整合性チェック、前処理、またはその他の高度な機能が追加されると、一部の内部アクセスが新しいコードを利用し、他の場所ではバイパスされるという 微妙なバグが発生する可能性があります。

アクセサ関数は、余分な手順が含まれるため、データフィールドを直接フェッチまたは保存するよりも効率が低くなる可能性があります[2]。ただし、このような関数はインライン化されることが多く、関数呼び出しのオーバーヘッドがなくなります。

組み立て

学生の                   構造体
    年齢         dd         
学生                   は終了します
                     .code 
student_get_age        proc      オブジェクトDWORD 
                      mov        ebx  object 
                      mov        eax  student.age [ ebx ] 
                      ret 
student_get_age        endp

student_set_age        proc      オブジェクトDWORD  age DWORD 
                      mov        ebx  object 
                      mov        eax  age 
                      mov        student.age [ ebx ]、 eax 
                      ret 
student_set_age        endp

C

ファイルstudent.h:

#ifndef _STUDENT_H 
#define _STUDENT_H

構造体 学生; /*不透明な構造*/ 
typedefstruct学生学生; _   

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" 

構造体 学生{ 
  int年齢; 
  char *名前; 
};

student * student_new int age char * name {     
  学生* s = malloc sizeof 学生));   
  s- > name = strdup name );  
  s- >年齢=年齢;  
  sを返す; 
}

void student_delete student * s {   
  無料s- >名前);
  無料s );
}

void student_set_age student * s int age {     
  s- >年齢=年齢;  
}

int student_get_age student * s {   
  s- >年齢を返す; 
}

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の老後=%i \ n " name old_age );  
  student_set_age s 21 ); 
  int new_age = student_get_age s );   
  printf "%sの新しい年齢=%i \ n " name new_age );  
  student_delete s );
  0を返す; 
}

ファイルMakefile内:

すべて アウトtxt ; cat $ <
 out.txt  main ; ./$<> $ @
 main  maino 学生o 
main.o student.o  studenth
きれい  ; $(RM  *。o アウトtxt メイン

C++

Student.hのファイル:

#ifndef STUDENT_H 
#define STUDENT_H

#include <文字列> 

クラス 学生{ 
パブリック
    Student const std :: string name );  

    const std :: string name ()const ;   
    void name const std :: string name );   

プライベート
    std :: string name_ ; 
};

#endif

Student.cppファイル:

#include "Student.h" 

Student :: Student const std :: string name name_ name {     
}

const std :: string Student :: name ()const {    
    name_を返す; 
}

void Student :: name const std :: string name {    
    name_ =名前;  
}

C#

この例は、特殊なタイプのクラスメンバーであるプロパティのC#の考え方を示しています。Javaとは異なり、明示的なメソッドは定義されていません。public'property'には、アクションを処理するためのロジックが含まれています。組み込み(宣言されていない)変数の使用に注意してくださいvalue

パブリック クラス Student  {
    プライベート 文字列 ;

    ///<summary> 
    ///学生の名前を取得または設定します
    ///</summary> 
    public  string  Name  { 
        get  {  return  name ;  } 
        set  {  name  =  value ;  } 
    } 
}

それ以降のC#バージョン(.NET Framework 3.5以降)では、この例は、プライベート変数を宣言せずに、次のように省略される場合がありますname

public  class  Student  { 
    public  string  Name  {  get ;  セット;  } 
}

省略された構文を使用するということは、基礎となる変数がクラス内から使用できなくなることを意味します。結果としてset、プロパティの一部は割り当てのために存在する必要があります。setアクセスは、特定のアクセス修飾子 を使用して制限できます。

public  class  Student  { 
    public  string  Name  {  get ;  プライベート セット;  } 
}

CommonLisp

Common Lisp Object Systemでは、クラス定義内のスロット指定で、:readerリーダーメソッド、セッターメソッド、アクセサーメソッド(リーダーメソッドとそれぞれのメソッド)を定義するためのオプションを(複数回でも):writer指定できます[3]スロットには、とを使用して名前から常に直接アクセスできます。スロットアクセサーオプションは、を使用する特殊なメソッドを定義します[4]:accessorsetfwith-slotsslot-valueslot-value

CLOS自体にはプロパティの概念はありませんが、MetaObject Protocol拡張機能は、オプションで生成されたものを含む、スロットのリーダーおよびライター関数名にアクセスする手段を指定し:accessorます。[5]

次の例は、これらのスロットオプションと直接スロットアクセスを使用した学生クラスの定義を示しています。

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

;; 計算されたプロパティゲッターの例(これは単にメソッドです)
defmethod  student-age  ((self  student ))
  -  get-universal-time  student-birthdate  self )))

;; 計算されたプロパティセッター内の直接スロットアクセスの例
defmethod  setf  student-age  new-age  self  student ))
  with-slots  birthdate  self 
    setf  birthdate  -  get-universal-time  new-age ))
    新時代))

;; スロットアクセスオプションはメソッドを生成するため、さらにメソッドを定義できます
defmethod  set-student-number  :before  new-number  self  student ))
  ;;また、新しい番号の学生がすでに存在するかどうかを確認できます。
  check-  new-number  integer  1  * )))と入力します。

D

Dは、getterおよびsetter関数の構文をサポートしています。言語のバージョン2では、getterおよびsetterのclass/structメソッドに@property属性が必要です。[6] [7]

クラス Student  { 
    privatechar  [ ] name_ ; // Getter @property char [] name { returnthis name_ ; } //セッター@propertychar [ ] name char [ ] name_in { returnthis name_ = name_in ; } } 
    
       
         
    
    
        
           
    

インスタンスは次のStudentように使用できます。

自動 学生 = 新しい 学生; 
学生name  =  "David" ;            // student.name( "David") auto student_name = studentと同じ効果
名前; // student.name()と同じ効果    

Delphi

これはDelphi言語の単純なクラスであり、プライベートフィールドにアクセスするためのパブリックプロパティの概念を示しています。

インターフェース

タイプ
  TStudent  =  class 
  strict  private 
    FName  string ; 
    プロシージャ SetName const  Value  string ; 
  public 
    ///<summary> 
    ///学生の名前を取得または設定します。
    /// </ summary>
    プロパティ  文字列 読み取り FName 書き込み SetName ; 
  終了;

//..。

実装

手順 TStudent SetName const  Value  string ; 
FNameを開始します
  :=; 終了;  


終了

Java

名前だけが保存されている学生を表す単純なクラスのこの例では、変数 がプライベート、つまりStudentクラスからのみ表示され、「setter」と「getter」がパブリック、つまり「getName()」と" setName(name)"メソッド。

パブリック クラス Student  {
    プライベート 文字列 ;

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

JavaScript

この例では、constructor-functionStudentを使用して、名前のみが格納されている学生を表すオブジェクトを作成します。

function  Student name  { 
  var  _name  =  name ;

  これgetName  =  function () { 
    return  _name ; 
  };

  これsetName  =  function value  {_ 
    name  =  value ; 
  }; 
}

または(非推奨の方法を使用してWebブラウザーでアクセサーを定義する):[8]

function  Student name ){ 
    var  _name  =  name ;
   
    これ__defineGetter __ 'name'  function () { 
        return  _name ; 
    });
   
    これ__defineSetter __ 'name'  function value  {_ 
        name  =  value ; 
    }); 
}

または(継承とES6アクセサー構文のプロトタイプを使用):

関数 Student name ){ 
    this _name  =  name ; 
}

学生プロトタイプ =  { 
    getname  { returnthis _ _name ; }、set name value { this _name = value ; } }; 
         
    
      
          
    

または(プロトタイプを使用せずに):

var  Student  =  { 
    get  name  { 
        returnthis  _name ; }、set name value { this _name = value ; } };
    
      
          
    

または(definePropertyを使用):

関数 Student name ){ 
    this _name  =  name ; 
}
オブジェクトdefineProperty Student .prototype 'name' { get function (){ return this ._name ; } set function value { this ._name = value ; } } ;  
      
         
    
      
          
    

Actionscript3.0

パッケージ
{
    パブリック クラス 学生
    {
        プライベート 変数_ 名前  文字列;
		
        public  function  get  name ()  String 
        {  
            return  _name ; 
        }

        パブリック 関数 セット   文字列  void 
        { 
            _name  =  value ; 
        } 
    } 
}

Objective-C

従来のObjective-C1.0構文を使用し、Ubuntu12.04でGNUstepで動作するものとして手動参照カウントを使用ます

@interface  Student  :NSObject 
{
    NSString * _name ; 
}

-  NSString * 名前; 
-  void setName:NSString * name ; 

@終わり

@implementation  Student

-  NSString * 名前 
{{
    return _name ; 
}

-  void setName:NSString * name 
{{
    [ _nameリリース]; 
    _name = [名前保持];   
}

@終わり

Mac OS X 10.6iOS 4、およびXcode3.2で使用されている新しいObjective-C2.0構文を使用して、上記と同じコードを生成します。

@interface  Student  :NSObject

@property nonatomic retain NSString * name ;    

@終わり

@implementation  Student

@synthesize name = _name ;   

@終わり

また、OS X10.8およびiOS6以降、 Xcode 4.4以降を使用すると、構文をさらに簡略化できます。

@interface  Student  :NSObject

@property nonatomic strong NSString * name ;    

@終わり

@implementation  Student

//ここには何も行かず、問題ありません。

@終わり

Perl

パッケージ 学生;

sub  new  { 
    bless  {}、 shift ; 
}

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

sub  get_name  { 
    my  $ self  =  shift ; 
    $ self -> { name };を返します。 }


1 ;

または、Class::Accessorを使用します

パッケージ 学生; 
ベースqw(Class :: Accessor)を使用し ます; __PACKAGE__- > follow_best_practice ; 


Student- > mk_accessors qw(name));

1 ;

または、Moose Object Systemを使用します:

パッケージ 学生; 
Mooseを使用し ます;

#Mooseは属性名をsetterとgetterとして使用し、readerとwriterのプロパティは
#それをオーバーライドして独自の名前を提供できるようにします。この場合、get_nameとset_name
 'name'  =>  is  =>  'rw'  isa  =>  'Str'  reader  =>  'get_name'  writer  =>  'set_name' );

1 ;

PHP

PHPは、「魔法のメソッド」__get__setオブジェクトのプロパティを定義します。[9]

名前だけが保存されている学生を表す単純なクラスのこの例では、変数 がプライベート、つまりStudentクラスからのみ表示され、「setter」と「getter」がパブリック、つまりgetName()andsetName('name')メソッドであることがわかります。

クラス Student 
{
    プライベート 文字列 $name ;

    / ** 
     *@returnstring名前。
     * / 
    public  function  getName () string 
    { 
        return  $ this- > name ; 
    }

    / ** 
     * @param string$newName設定する名前。
     * / 
    public  function  setName string  $ newName  void 
    { 
        $ this- > name  =  $ newName ; 
    } 
}

Python

この例では、1つの変数、ゲッター、およびセッターを持つPythonクラスを使用しています。

class  Student 
    #Initializer 
    def  __init __ self  name  str  ->  None 
        #学生の名前
        selfを保持するインスタンス変数_name  =  name

    #ゲッターメソッド
    @property def 
    name  self 
        returnself  _名前

    #セッターメソッド
    @name setter 
    def  name self  new_name ):
        self _name  =  new_name
>>> bob  =  Student "Bob" 
>>> bob 名前 
ボブ
>>>ボブname  =  "Alice" 
>>> bob 名前 
アリス
>>>ボブ_name  =  "Charlie"  #セッターをバイパスする
>>> bob _name  #ゲッター
チャーリーをバイパスする

ラケット

Racketでは、オブジェクトシステムは、モジュールとユニットに加えて提供されるコードを整理する方法です。言語の他の部分と同様に、オブジェクトシステムにはファーストクラスの値があり、レキシカルスコープはオブジェクトとメソッドへのアクセスを制御するために使用されます。

#langラケット
define  student%
  class  object%
    init-field  name 
    define / public  get-name  name 
    define / public  set-name! new-name  set! name  new-name ))
    超新品)))

define  s  new  student% [ name  "Alice" ]))
send  s  get-name                        ; => "Alice" 
s set-nameを送信します!  "Bob" s get-nameを送信します; =>「ボブ」  
                         

構造体定義は、新しいタイプの値を定義するための代替方法であり、明示的に必要な場合はミューテーターが存在します。

#lang Racket 
struct student   name  :mutable 
define  s  student  "Alice" ))
set-student-name! s  "Bob" 
student-name  s                         ; =>「ボブ」

ルビー

Rubyでは、個々のアクセサーメソッドとミューテーターメソッドを定義するか、メタプログラミングコンストラクトを使用するattr_readerattr_accessor、クラス内のプライベート変数を宣言し、それぞれに読み取り専用または読み取り/書き込みのパブリックアクセスを提供するために使用できます。

個々のアクセサーメソッドとミューテーターメソッドを定義すると、データの前処理または検証のためのスペースが作成されます

クラス Studentdefname 
  @name end _  _
    
  

  def  name = value 
    @name = value 
  end 
end

@name暗黙の変数 への読み取り専用の単純なパブリックアクセス

クラス Studentattr_reader 
  name end 

@name暗黙の変数 への読み取り/書き込みの単純なパブリックアクセス

クラス Studentattr_accessor 
  name end 

Smalltalk

  age: aNumber 
     "0より大きく150未満の場合はレシーバーの年齢をaNumberに設定します"aNumber   0 から: 150の間)
        ifTrue: [ age  :=  aNumber ]

スウィフト

class  Student  { 
    private  var  _name  String  =  ""

    var  name  String  { 
        get  { 
            returnself  _ _name } set { self _name = newValue } } }
        
         
              
        
    

Visual Basic.NET

この例は、クラスで使用されるプロパティのVB.NETの考え方を示しています。C#と同様に、GetandSetメソッドの明示的な使用法があります。

パブリック クラス の学生

    Private  _name  As  String

    パブリック プロパティ ()
        Get 
            Return  _name 
        End  Get 
        Set ByVal  value 
            _name  =  value 
        End  Set 
    End  Property

エンド クラス

VB.NET 2010では、自動実装プロパティを使用して、GetおよびSet構文を使用せずにプロパティを作成できます。_nameプロパティに対応するために、と呼ばれる非表示の変数がコンパイラによって作成されることに注意してくださいname指定されたクラス内で別の変数を使用する_nameと、エラーが発生します。基になる変数への特権アクセスは、クラス内から利用できます。

パブリック クラス 学生
    パブリック プロパティ  AsStringEnd  Class _ 
_ 

も参照してください

参照

  1. ^ Stephen Fuqua(2009)。「C#3.0の自動プロパティ」2011年5月13日にオリジナルからアーカイブされました2009年10月19日取得
  2. ^ ティムリー(1998-07-13)。「アクセサ機能の実行時効率」
  3. ^ 「CLHS:マクロDEFCLASS」2011年3月29日取得
  4. ^ 「CLHS:7.5.2スロットへのアクセス」2011年3月29日取得
  5. ^ 「MOP:スロット定義」2011年3月29日取得
  6. ^ 「関数-Dプログラミング言語」2013年1月13日取得{{cite web}}:CS1 maint:url-status(link
  7. ^ 「Dスタイル」2013年2月1日取得
  8. ^ "Object.prototype .__ defineGetter __()-JavaScript|MDN"developer.mozilla.org 2021-07-06を取得
  9. ^ 「PHP:オーバーロード-手動」www.php.net 2021-07-06を取得