정적 클래스 및 멤버에 대한 생각과 모범 사례 [닫기]


11

정적 멤버 또는 전체 정적 클래스에 대한 생각과 업계 모범 사례에 대해 매우 궁금합니다. 이것에 대한 단점이 있습니까? 아니면 안티 패턴에 참여합니까?

기능을 제공하기 위해 클래스를 인스턴스화 할 필요가 없거나 필요로하지 않는다는 점에서 이러한 엔티티를 "유틸리티 클래스 / 멤버"로 간주합니다.

이것에 대한 일반적인 생각과 업계 모범 사례는 무엇입니까?

아래 참조 클래스 및 멤버를 참조하여 내가 참조하는 것을 설명하십시오.

// non-static class with static members
//
public class Class1
{
    // ... other non-static members ...

    public static string GetSomeString()
    {
        // do something
    }
}

// static class
//
public static class Class2
{
    // ... other static members ...

    public static string GetSomeString()
    {
        // do something
    }
}

미리 감사드립니다!


1
정적 클래스 및 정적 메소드에 대한 MSDN 기사 는 상당히 좋은 처리 방법을 제공합니다.
Robert Harvey

1
@Robert Harvey : 참조한 기사는 유용하지만 정적 클래스를 사용할 때 모범 사례와 함정에 대해서는별로 설명하지 않습니다.
Bernard

답변:


18

일반적으로 정적, 특히 모든 종류의 정적 상태를 피하십시오.

왜?

  1. 정적은 동시성에 문제를 일으 킵니다. 인스턴스는 하나뿐이므로 동시 실행간에 자연스럽게 공유됩니다. 이러한 공유 리소스는 동시 프로그래밍의 단점이며 종종 공유 할 필요 가 없습니다 .

  2. 정전기는 장치 테스트에 문제를 일으 킵니다. 솔트 가치가있는 모든 단위 테스트 프레임 워크는 동시에 테스트를 실행합니다. 그런 다음 # 1에 도달합니다. 설상가상으로, 모든 셋업 / 티어 다운 작업과 테스트를 복잡하게 만들고 셋업 코드를 "공유"하려고 시도하는 해커입니다.

작은 것들도 많이 있습니다. 정적은 융통성이없는 경향이 있습니다. 인터페이스 할 수없고, 재정의 할 수 없으며, 구성 타이밍을 제어 할 수 없으며, 제네릭에서 잘 사용할 수 없습니다. 실제로 버전을 지정할 수 없습니다.

정적 사용은 확실히 있습니다. 상수 값이 효과적입니다. 단일 클래스에 맞지 않는 순수한 메소드는 여기서 훌륭하게 작동 할 수 있습니다.

그러나 일반적으로 피하십시오.


동시성에 대한 무능의 정도가 궁금합니다. 당신은 그것을 확장 할 수 있습니까? 분리없이 멤버에 액세스 할 수 있다는 것은 완벽한 의미입니다. 정적에 대한 사용 사례는 상수 값과 순수 / 유틸리티 메소드에 주로 사용합니다. 이것이 정적에 대한 최고이고 99 %의 유스 케이스라면, 그것은 내게 편안함을줍니다. 또한 답을 +1하십시오. 훌륭한 정보.
토마스 스트링거

@ThomasStringer-스레드 / 태스크 사이의 터치 포인트가 많을수록 동시성 문제 및 / 또는 동기화 수행시 성능 손실이 발생할 가능성이 높아집니다.
Telastyn

따라서 한 스레드가 현재 정적 멤버에 액세스하는 경우 다른 스레드가 소유 스레드가 자원을 해제 할 때까지 기다려야합니까?
토마스 스트링거

@ThomasStringer-아마도 아닐 수도 있습니다. 정적은 (거의 대부분의 언어에서) 이와 관련하여 다른 공유 리소스와 다르지 않습니다.
Telastyn

@ThomasStringer : 불행히도 회원을 표시하지 않으면 실제로 이보다 더 나쁩니다 volatile. 휘발성 데이터가없는 메모리 모델에 대해서는 보증이 없으므로 한 스레드에서 변수를 변경하면 즉시 또는 전혀 반영되지 않을 수 있습니다.
Phoshi

17

기능이 "순수한"경우 아무런 문제가 없습니다. 순수한 기능은 입력 매개 변수에서만 작동하며이를 기반으로 결과를 제공합니다. 전역 상태 나 외부 컨텍스트에 의존하지 않습니다.

자신의 코드 예제를 보면 :

public class Class1
{
    public static string GetSomeString()
    {
        // do something
    }
}

이 기능에는 매개 변수가 없습니다. 따라서 순수한 것은 아닙니다 (이 함수의 유일한 순수한 구현은 상수를 반환하는 것입니다). 나는이 예제가 실제 문제를 대표하지 않는다고 가정합니다. 이것은 아마도 순수한 기능이 아니라고 지적합니다.

다른 예를 보자.

public static bool IsOdd(int number) { return (number % 2) == 1; }

이 함수가 정적 인 것은 아무 문제가 없습니다. 우리는 이것을 확장 기능으로 만들어서 클라이언트 코드를 더 읽기 쉽게 만들 수 있습니다. 확장 함수 기본적으로 특별한 종류의 정적 함수입니다.

Telastyn은 동시성을 정적 멤버의 잠재적 인 문제로 올바르게 언급합니다. 그러나이 함수는 공유 상태를 사용하지 않으므로 여기에는 동시성 문제가 없습니다. 수천 개의 스레드가 동시성 문제없이이 함수를 동시에 호출 할 수 있습니다.

.NET 프레임 워크에서 확장 메서드는 꽤 오랫동안 존재했습니다. LINQ 에는 많은 확장 함수 (예 : Enumerable.Where () , Enumerable.First () , Enumerable.Single () 등)가 포함되어 있습니다. 우리는 이것들을 나쁜 것으로 보지 않습니까?

단위 테스트는 코드가 대체 가능한 추상화를 사용하는 경우에 도움이되므로 단위 테스트는 시스템 코드를 테스트 이중으로 대체 할 수 있습니다. 정적 함수는 이러한 유연성을 금지하지만 이는 실제 데이터 액세스 계층을 가짜 데이터 액세스 계층 으로 대체하려는 아키텍처 계층 경계에서 주로 중요 합니다.

그러나 어떤 숫자가 홀수인지 짝수인지에 따라 다르게 동작하는 객체에 대한 테스트를 작성할 때 실제로 IsOdd()함수를 대체 구현 으로 대체 할 필요는 없습니다 . 마찬가지로 Enumerable.Where()테스트 목적으로 다른 구현 을 제공해야하는 시점도 알 수 없습니다 .

이 함수에 대한 클라이언트 코드의 가독성을 살펴 보자.

옵션 a (확장 메소드로 선언 된 함수 포함) :

public void Execute(int number) {
    if (number.IsOdd())
        // Do something
}

옵션 b :

public void Execute(int number) {
    var helper = new NumberHelper();
    if (helper.IsOdd(number))
        // Do something
}

정적 (확장) 함수는 첫 번째 코드 조각을 훨씬 더 읽기 쉽게 만들고 가독성은 중요하므로 정적 함수를 사용하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.