다음을 통해 공유


속성과 메서드 간의 선택

일반적으로 메서드는 동작을 나타내고 속성은 데이터를 나타냅니다. 속성은 필드처럼 사용됩니다. 즉, 계산 과정이 복잡하지 않거나 부작용을 생성하지 않아야 합니다. 다음 지침을 위반하지 않는 경우 경험이 적은 개발자에게는 속성을 사용하는 것이 더 쉬우므로 메서드보다 속성을 사용하는 것이 좋습니다.

멤버가 형식의 논리적 특성을 나타내는 경우 속성을 사용할 수 있습니다.

예를 들어, BorderStyle은 테두리 스타일이 ListView의 특성이므로 속성입니다.

속성 값이 프로세스 메모리에 저장되어 있고 해당 속성이 값에 대한 액세스를 제공하는 경우 메서드보다 속성을 사용합니다.

다음 코드 예제에서는 이러한 지침을 보여 줍니다. EmployeeRecord 클래스는 전용 필드에 액세스할 수 있도록 하는 두 개의 속성을 정의합니다. 완전한 예제는 이 항목의 끝에 나옵니다.

Public Class EmployeeRecord

    Private employeeIdValue as Integer
    Private departmentValue as Integer

    Public Sub New()
    End Sub

    Public Sub New (id as Integer, departmentId as Integer)
        EmployeeId = id
        Department = departmentId
    End Sub

    Public Property Department as Integer
        Get 
            Return departmentValue
        End Get
        Set 
            departmentValue = value
        End Set
    End Property

    Public Property EmployeeId as Integer
        Get 
            Return employeeIdValue
        End Get
        Set 
            employeeIdValue = value
        End Set
    End Property
    Public Function Clone() as EmployeeRecord
        Return new EmployeeRecord(employeeIdValue, departmentValue)
    End Function
End Class
public class EmployeeRecord
{
    private int employeeId;
    private int department;
    public EmployeeRecord()
    {
    }
    public  EmployeeRecord (int id, int departmentId)
    {
        EmployeeId = id;
        Department = departmentId;
    }
    public int Department
    {
        get {return department;}
        set {department = value;}
    }
    public int EmployeeId
    {
        get {return employeeId;}
        set {employeeId = value;}
    }
    public EmployeeRecord Clone()
    {
        return new EmployeeRecord(employeeId, department);
    }
}
public ref class EmployeeRecord
{
private:
    int employeeId;
    int department;

public:
    EmployeeRecord()
    {
    }

    EmployeeRecord(int id, int departmentId)
    {
        EmployeeId = id;
        Department = departmentId;
    }

    property int Department
    {
        int get() {return department;}
        void set(int value) {department = value;}
    }

    property int EmployeeId
    {
        int get() {return employeeId;}
        void set(int value) {employeeId = value;}
    }

    EmployeeRecord^ Clone()
    {
        return gcnew EmployeeRecord(employeeId, department);
    }
};

다음과 같은 경우 속성보다 메서드를 사용합니다.

  • 작업이 필드 집합보다 더 느린 경우. 스레드가 차단되는 것을 방지하기 위해 비동기 작업 버전을 제공할 경우에도 이 작업은 너무 많은 리소스를 차지하여 속성이 되지 못할 가능성이 높습니다. 특히 초기화를 위한 액세스 한 번을 제외하고 네트워크나 파일 시스템에 액세스하는 작업은 속성이 아니라 메서드여야 합니다.

  • 해당 작업이 Object.ToString method 등의 변환인 경우

  • 매개 변수가 변경되지 않아도 작업이 호출될 때마다 다른 결과를 반환하는 경우. 예를 들어, NewGuid 메서드는 호출될 때마다 다른 값을 반환합니다.

  • 작업에 눈에 띄는 상당한 부작용이 있는 경우. 내부 캐시를 채우는 것은 대개 눈에 띄는 부작용으로 간주되지 않습니다.

  • 작업이 내부 상태의 복사본을 반환하는 경우(스택에 반환된 값 형식 개체의 복사본 제외)

  • 작업이 배열을 반환하는 경우

작업이 배열을 반환하는 경우 메서드를 사용합니다. 내부 배열을 유지하기 위해서는 해당 속성에서 사용한 배열에 대한 참조가 아닌 배열의 전체 복사본을 반환해야 하기 때문입니다. 이러한 이유와 개발자가 속성을 필드처럼 사용하는 이유로 인해 코드가 매우 비효율적이 될 수 있습니다. 다음 코드 예제에서는 속성을 사용하여 배열을 반환하는 방법을 보여 줍니다. 완전한 예제는 이 항목의 끝에 표시됩니다.

Public Class EmployeeData

    Dim data as EmployeeRecord()
    Public Sub New(data as EmployeeRecord())
        Me.data = data
    End Sub
    Public ReadOnly Property Employees as EmployeeRecord()
        Get
            Dim newData as EmployeeRecord() = CopyEmployeeRecords()
            Return newData
        End Get
    End Property

    Private Function CopyEmployeeRecords() as EmployeeRecord()
        Dim newData(UBound(data)) as EmployeeRecord
        For i as Integer = 0 To UBound(data)
            newData(i) = data(i).Clone()
        Next i
        Console.WriteLine ("EmployeeData: cloned employee data.")
        Return newData
    End Function
End Class
public class EmployeeData
{
    EmployeeRecord[] data;
    public EmployeeData(EmployeeRecord[] data)
    {
        this.data = data;
    }
    public EmployeeRecord[] Employees
    {
        get 
        {
            EmployeeRecord[] newData = CopyEmployeeRecords();
            return newData;
        }
    }
    EmployeeRecord[] CopyEmployeeRecords()
    {
        EmployeeRecord[] newData = new EmployeeRecord[data.Length];
        for(int i = 0; i< data.Length; i++)
        {
            newData[i] = data[i].Clone();
        }
        Console.WriteLine ("EmployeeData: cloned employee data.");
        return newData;
    }
}
public ref class EmployeeData
{
private:
    array<EmployeeRecord^>^ data;

public:
    EmployeeData(array<EmployeeRecord^>^ data)
    {
        this->data = data;
    }

    property array<EmployeeRecord^>^ Employees
    {
        array<EmployeeRecord^>^ get()
        {
            array<EmployeeRecord^>^ newData = CopyEmployeeRecords();
            return newData;
        }
    }

private:
    array<EmployeeRecord^>^ CopyEmployeeRecords()
    {
        array<EmployeeRecord^>^ newData = gcnew array<EmployeeRecord^>(data->Length);
        for(int i = 0; i< data->Length; i++)
        {
            newData[i] = data[i]->Clone();
        }
        Console::WriteLine ("EmployeeData: cloned employee data.");

        return newData;
    }
};

이 클래스를 사용하는 개발자는 속성이 필드 액세스보다 리소스를 많이 차지 않는다고 가정하고 다음 코드 예제에서와 같이 이러한 가정을 기반으로 응용 프로그램 코드를 작성합니다.

Public Class RecordChecker
    Public Shared Function  FindEmployees( _
         dataSource as EmployeeData, _
         department as Integer) as Collection(Of Integer)

        Dim storage as Collection(Of Integer) = new Collection(Of Integer)()
        Console.WriteLine("Record checker: beginning search.")
        For i as Integer = 0 To UBound(dataSource.Employees)
            If dataSource.Employees(i).Department = department
                Console.WriteLine("Record checker: found match at {0}.", i)
                storage.Add(dataSource.Employees(i).EmployeeId)
                Console.WriteLine("Record checker: stored match at {0}.", i)
            Else 
                Console.WriteLine("Record checker: no match at {0}.", i)
            End If
        Next i
        Return storage
    End Function
End Class
public class RecordChecker
{
    public static Collection<int> FindEmployees(EmployeeData dataSource, 
             int department)
    {
        Collection<int> storage = new Collection<int>();
        Console.WriteLine("Record checker: beginning search.");
        for (int i = 0; i < dataSource.Employees.Length; i++)
        {
            if (dataSource.Employees[i].Department == department)
            {
                Console.WriteLine("Record checker: found match at {0}.", i);
                storage.Add(dataSource.Employees[i].EmployeeId);
                Console.WriteLine("Record checker: stored match at {0}.", i);
            }
            else 
            {
                Console.WriteLine("Record checker: no match at {0}.", i);
            }
        }
        return storage;
    }
}
public class RecordChecker
{
public:
    static Collection<int>^ FindEmployees(EmployeeData^ dataSource,
             int department)
    {
        Collection<int>^ storage = gcnew Collection<int>();
        Console::WriteLine("Record checker: beginning search.");
        for (int i = 0; i < dataSource->Employees->Length; i++)
        {
            if (dataSource->Employees[i]->Department == department)
            {
                Console::WriteLine("Record checker: found match at {0}.", i);
                storage->Add(dataSource->Employees[i]->EmployeeId);
                Console::WriteLine("Record checker: stored match at {0}.", i);
            }
            else
            {
                Console::WriteLine("Record checker: no match at {0}.", i);
            }
        }
        return storage;
    }
};

Employees 속성은 각 루프 반복에서 액세스되고 부서가 일치해도 액세스됩니다. 속성에 액세스할 때마다 직원 배열의 복사본이 만들어져 간단히 사용된 다음 가비지 수집을 필요로 합니다. Employees를 메서드로 구현하여 이 작업이 필드에 액세스하는 것보다 더 많은 리소스를 차지함을 개발자에게 나타낼 수 있습니다. 개발자는 메서드를 한 번 호출하고 메서드 호출 결과를 캐시하여 해당 작업을 수행합니다.

예제

다음 코드 예제에서는 속성 액세스가 리소스를 많이 차지 않는다고 가정하는 완전한 응용 프로그램을 보여 줍니다. EmployeeData 클래스는 배열의 복사본을 반환하는 속성을 잘못 정의합니다.

Imports System
Imports System.Collections.ObjectModel

Namespace Examples.DesignGuidelines.Properties
    Public Class EmployeeRecord

        Private employeeIdValue as Integer
        Private departmentValue as Integer

        Public Sub New()
        End Sub

        Public Sub New (id as Integer, departmentId as Integer)
            EmployeeId = id
            Department = departmentId
        End Sub

        Public Property Department as Integer
            Get 
                Return departmentValue
            End Get
            Set 
                departmentValue = value
            End Set
        End Property

        Public Property EmployeeId as Integer
            Get 
                Return employeeIdValue
            End Get
            Set 
                employeeIdValue = value
            End Set
        End Property
        Public Function Clone() as EmployeeRecord
            Return new EmployeeRecord(employeeIdValue, departmentValue)
        End Function
    End Class

Public Class EmployeeData

    Dim data as EmployeeRecord()
    Public Sub New(data as EmployeeRecord())
        Me.data = data
    End Sub
    Public ReadOnly Property Employees as EmployeeRecord()
        Get
            Dim newData as EmployeeRecord() = CopyEmployeeRecords()
            Return newData
        End Get
    End Property

    Private Function CopyEmployeeRecords() as EmployeeRecord()
        Dim newData(UBound(data)) as EmployeeRecord
        For i as Integer = 0 To UBound(data)
            newData(i) = data(i).Clone()
        Next i
        Console.WriteLine ("EmployeeData: cloned employee data.")
        Return newData
    End Function
End Class

Public Class RecordChecker
    Public Shared Function  FindEmployees( _
         dataSource as EmployeeData, _
         department as Integer) as Collection(Of Integer)

        Dim storage as Collection(Of Integer) = new Collection(Of Integer)()
        Console.WriteLine("Record checker: beginning search.")
        For i as Integer = 0 To UBound(dataSource.Employees)
            If dataSource.Employees(i).Department = department
                Console.WriteLine("Record checker: found match at {0}.", i)
                storage.Add(dataSource.Employees(i).EmployeeId)
                Console.WriteLine("Record checker: stored match at {0}.", i)
            Else 
                Console.WriteLine("Record checker: no match at {0}.", i)
            End If
        Next i
        Return storage
    End Function
End Class
    Public Class Tester
        Public Shared Sub Main()
            Dim records(2) as EmployeeRecord
            Dim r0 as EmployeeRecord = new EmployeeRecord()
            r0.EmployeeId = 1
            r0.Department = 100
            records(0) = r0
            Dim r1 as EmployeeRecord = new EmployeeRecord()
            r1.EmployeeId = 2
            r1.Department = 100
            records(1) = r1
            Dim r2 as EmployeeRecord = new EmployeeRecord()
            r2.EmployeeId = 3
            r2.Department = 101
            records(2) = r2
            Dim empData as EmployeeData = new EmployeeData(records)
            Dim hits as Collection(Of Integer)= _ 
                RecordChecker.FindEmployees(empData, 100)
            For Each i as Integer In hits
                Console.WriteLine("found employee {0}", i)
            Next i
        End Sub
    End Class
End Namespace
using System;
using System.Collections.ObjectModel;
namespace Examples.DesignGuidelines.Properties
{
    public class EmployeeRecord
    {
        private int employeeId;
        private int department;
        public EmployeeRecord()
        {
        }
        public  EmployeeRecord (int id, int departmentId)
        {
            EmployeeId = id;
            Department = departmentId;
        }
        public int Department
        {
            get {return department;}
            set {department = value;}
        }
        public int EmployeeId
        {
            get {return employeeId;}
            set {employeeId = value;}
        }
        public EmployeeRecord Clone()
        {
            return new EmployeeRecord(employeeId, department);
        }
    }

public class EmployeeData
{
    EmployeeRecord[] data;
    public EmployeeData(EmployeeRecord[] data)
    {
        this.data = data;
    }
    public EmployeeRecord[] Employees
    {
        get 
        {
            EmployeeRecord[] newData = CopyEmployeeRecords();
            return newData;
        }
    }
    EmployeeRecord[] CopyEmployeeRecords()
    {
        EmployeeRecord[] newData = new EmployeeRecord[data.Length];
        for(int i = 0; i< data.Length; i++)
        {
            newData[i] = data[i].Clone();
        }
        Console.WriteLine ("EmployeeData: cloned employee data.");
        return newData;
    }
}

public class RecordChecker
{
    public static Collection<int> FindEmployees(EmployeeData dataSource, 
             int department)
    {
        Collection<int> storage = new Collection<int>();
        Console.WriteLine("Record checker: beginning search.");
        for (int i = 0; i < dataSource.Employees.Length; i++)
        {
            if (dataSource.Employees[i].Department == department)
            {
                Console.WriteLine("Record checker: found match at {0}.", i);
                storage.Add(dataSource.Employees[i].EmployeeId);
                Console.WriteLine("Record checker: stored match at {0}.", i);
            }
            else 
            {
                Console.WriteLine("Record checker: no match at {0}.", i);
            }
        }
        return storage;
    }
}
    public class Tester
    {
        public static void Main()
        {
            EmployeeRecord[] records  = new EmployeeRecord[3];
            EmployeeRecord r0  = new EmployeeRecord();
            r0.EmployeeId = 1;
            r0.Department = 100;
            records[0] = r0;
            EmployeeRecord r1  = new EmployeeRecord();
            r1.EmployeeId = 2;
            r1.Department = 100;
            records[1] = r1;
            EmployeeRecord r2  = new EmployeeRecord();
            r2.EmployeeId = 3;
            r2.Department = 101;
            records[2] = r2;
            EmployeeData empData = new EmployeeData(records);
            Collection<int> hits = RecordChecker.FindEmployees(empData, 100);
            foreach (int i in hits)
            {
                Console.WriteLine("found employee {0}", i);
            }
        }
    }
}

using namespace System;
using namespace System::Collections::ObjectModel;

namespace Examples { namespace DesignGuidelines { namespace Properties
{
    public ref class EmployeeRecord
    {
    private:
        int employeeId;
        int department;

    public:
        EmployeeRecord()
        {
        }

        EmployeeRecord(int id, int departmentId)
        {
            EmployeeId = id;
            Department = departmentId;
        }

        property int Department
        {
            int get() {return department;}
            void set(int value) {department = value;}
        }

        property int EmployeeId
        {
            int get() {return employeeId;}
            void set(int value) {employeeId = value;}
        }

        EmployeeRecord^ Clone()
        {
            return gcnew EmployeeRecord(employeeId, department);
        }
    };

    public ref class EmployeeData
    {
    private:
        array<EmployeeRecord^>^ data;

    public:
        EmployeeData(array<EmployeeRecord^>^ data)
        {
            this->data = data;
        }

        property array<EmployeeRecord^>^ Employees
        {
            array<EmployeeRecord^>^ get()
            {
                array<EmployeeRecord^>^ newData = CopyEmployeeRecords();
                return newData;
            }
        }

    private:
        array<EmployeeRecord^>^ CopyEmployeeRecords()
        {
            array<EmployeeRecord^>^ newData = gcnew array<EmployeeRecord^>(data->Length);
            for(int i = 0; i< data->Length; i++)
            {
                newData[i] = data[i]->Clone();
            }
            Console::WriteLine ("EmployeeData: cloned employee data.");

            return newData;
        }
    };

    public class RecordChecker
    {
    public:
        static Collection<int>^ FindEmployees(EmployeeData^ dataSource,
                 int department)
        {
            Collection<int>^ storage = gcnew Collection<int>();
            Console::WriteLine("Record checker: beginning search.");
            for (int i = 0; i < dataSource->Employees->Length; i++)
            {
                if (dataSource->Employees[i]->Department == department)
                {
                    Console::WriteLine("Record checker: found match at {0}.", i);
                    storage->Add(dataSource->Employees[i]->EmployeeId);
                    Console::WriteLine("Record checker: stored match at {0}.", i);
                }
                else
                {
                    Console::WriteLine("Record checker: no match at {0}.", i);
                }
            }
            return storage;
        }
    };

    public ref class Tester
    {
    public:
        static void Main()
        {
            array<EmployeeRecord^>^ records = gcnew array<EmployeeRecord^>(3);
            EmployeeRecord^ r0  = gcnew EmployeeRecord();
            r0->EmployeeId = 1;
            r0->Department = 100;
            records[0] = r0;
            EmployeeRecord^ r1  = gcnew EmployeeRecord();
            r1->EmployeeId = 2;
            r1->Department = 100;
            records[1] = r1;
            EmployeeRecord^ r2  = gcnew EmployeeRecord();
            r2->EmployeeId = 3;
            r2->Department = 101;
            records[2] = r2;
            EmployeeData^ empData = gcnew EmployeeData(records);
            Collection<int>^ hits = RecordChecker::FindEmployees(empData, 100);
            for each (int i in hits)
            {
                Console::WriteLine("found employee {0}", i);
            }
        }
    };
}}}

Portions Copyright 2005 Microsoft Corporation. All rights reserved.

Portions Copyright Addison-Wesley Corporation. All rights reserved.

디자인 지침에 자세한 내용은 참조를 "Framework 디자인 지침: 규칙, 숙어, 및 재사용에 대 한 패턴입니다.NET 라이브러리"도 서 Krzysztof Cwalina와 Brad Abrams, 게시 Addison-wesley, 2005.

참고 항목

개념

속성 디자인

기타 리소스

멤버 디자인 지침

클래스 라이브러리 개발을 위한 디자인 지침