Java-완전히 정적 인 클래스를 갖는 것은 나쁜 생각입니까?


16

나는 더 큰 솔로 프로젝트를 진행하고 있으며 현재 인스턴스를 만들 이유가없는 몇 가지 클래스가 있습니다.

예를 들어, 내 주사위 클래스는 현재 모든 데이터를 정적으로 저장하고 모든 메소드도 정적입니다. 주사위를 굴리고 새로운 가치를 얻고 싶을 때 그냥 사용하기 때문에 초기화 할 필요가 없습니다 Dice.roll().

나는 이와 같은 하나의 주요 기능만을 가진 몇 가지 비슷한 클래스를 가지고 있으며 모든 이벤트를 담당하는 일종의 "컨트롤러"클래스에서 작업을 시작하려고합니다 (플레이어가 움직일 때와 현재 턴 그것은) 그리고 나는이 수업에 대해 동일한 아이디어를 따를 수 있음을 발견했습니다. 나는이 특정 클래스에 대해 여러 객체를 만들 계획이 없으므로 완전히 정적으로 만드는 것은 나쁜 생각입니까?

Java와 관련하여 이것이 "나쁜 습관"으로 간주되는지 궁금합니다. 내가 본 것에서 커뮤니티는이 주제에 대해 분리되어있는 것 같습니다. 어쨌든, 나는 이것에 대한 약간의 토론을 좋아할 것이고 리소스에 대한 링크도 훌륭 할 것입니다!


1
프로그램이 완전히 절차적인 경우 왜 Java를 선택 했습니까?
Laiv

12
이 클래스들에 대한 단위 테스트를 작성 해보면 사람들이 왜 정적 상태에 액세스하는 정적 메소드를 좋아하지 않는지 알아낼 것입니다.
Joeri Sebrechts

@Laiv 저는 여전히 프로그래밍에 익숙하지 않습니다. 약 1 년의 C ++, 이번 학기에는 Java 클래스를 사용하고 있으며 특히 그래픽 라이브러리를 더 좋아하기 시작합니다.
HexTeke


5
정적 클래스와 관련하여. 정적 메소드가 순수한 경우 (상태를 유지하지 않으면 입력 인수와 리턴 유형이 있음) 걱정할 것이 없습니다
Laiv

답변:


21

진정으로 정적 클래스와 아무것도 잘못이 정적 . 다시 말해서, 메소드의 출력이 변경되도록하는 내부 상태는 없습니다.

Dice.roll()단순히 1에서 6까지 새로운 난수를 반환하는 경우 상태가 변경되지 않습니다. 물론 Random인스턴스를 공유하고 있지만 정의에 따라 상태가 변경되면 출력이 항상 무작위로 잘 될 것이라고는 생각하지 않습니다. 또한 스레드 안전하므로 문제가 없습니다.

종종 최종 "Helper"또는 개인 생성자와 정적 멤버가있는 기타 유틸리티 클래스가 표시됩니다. 개인 생성자는 논리를 포함하지 않으며 누군가 클래스를 인스턴스화하지 못하도록합니다. 최종 수정자는이 아이디어가 당신이 파생시키려는 클래스가 아니라는 가정을 가져옵니다. 단지 유틸리티 클래스 일뿐입니다. 제대로된다면 싱글턴이나 다른 클래스 멤버가 없어야합니다.

이 지침을 따르고 싱글 톤을 만들지 않는 한, 이것에 전혀 문제가 없습니다. 당신은 컨트롤러 클래스를 언급,이 능력은 거의 것입니다 확실히 내가 정적 방법을 사용하여에 대해 조언을 할 수 있도록, 상태 변화를 필요로한다. 정적 유틸리티 클래스에 크게 의존 할 수 있지만 정적 유틸리티 클래스로 만들 수는 없습니다 .


수업의 상태 변화 는 무엇입니까 ? 음수는 정의에 의해 결정적이지 않기 때문에 1 초 동안 임의의 숫자를 제외 시키므로 반환 값은 자주 변경됩니다.

순수한 함수는 결정 론적 함수입니다. 즉, 주어진 입력에 대해 하나의 정확한 결과를 얻습니다. 정적 메소드가 순수한 함수가되기를 원합니다. Java에는 정적 메소드의 동작을 조정하여 상태를 유지하는 방법이 있지만 좋은 아이디어는 아닙니다. 메소드를 static 으로 선언 하면 일반적인 프로그래머는 박쥐가 순수한 함수라고 가정합니다. 예상되는 동작에서 벗어나는 것은 프로그램에서 버그를 생성하는 경향이 있으며 일반적으로 말하면 피해야합니다.

싱글 톤은 "순수 함수"와 반대되는 정적 메소드를 포함하는 클래스입니다. 하나의 정적 개인 멤버는 클래스의 내부에 유지되며 정확히 하나의 인스턴스가 있는지 확인하는 데 사용됩니다. 이것은 모범 사례가 아니며 여러 가지 이유로 나중에 문제를 일으킬 수 있습니다. 우리가 무엇을 말하는지 알기 위해, 여기 싱글 톤의 간단한 예가 있습니다 :

// DON'T DO THIS!
class Singleton {
  private String name; 
  private static Singleton instance = null;

  private Singleton(String name) {
    this.name = name;
  }

  public static Singleton getInstance() {
    if(instance == null) {
      instance = new Singleton("George");
    }
    return instance;
  }

  public getName() {
    return name;
  }
}

assert Singleton.getInstance().getName() == "George"

7
더블 6이 굴릴 때 어떤 일이 발생하는지 테스트하려면 정적 난수 생성기가있는 정적 클래스가 있으므로 여기에 붙어 있습니다. 따라서 Dice.roll()“글로벌 상태 없음”규칙에 대한 유효한 예외는 아닙니다.
David Arno

1
@HexTeke 업데이트 된 답변입니다.
Neil

1
@DavidArno 사실이지만,에 대한 단일 호출을 테스트하면 실제로 문제가 있다고 가정합니다 random.nextInt(6) + 1. ;)
Neil

3
@ Neil, 사과, 나는 나 자신을 잘 설명하지 못했습니다. 우리는 난수 시퀀스를 테스트하지 않고 다른 테스트를 돕기 위해 해당 시퀀스에 영향을 미칩니다. 예를 들어 RollAndMove()더블 6을 공급할 때 다시 굴리는 테스트를하는 경우 가장 쉬운 방법 Dice은 난수 생성기 를 조롱하는 것 입니다. Ergo Dice는 정적 랜덤 생성기를 사용하는 정적 클래스가되고 싶지 않습니다.
David Arno

13
그래도 업데이트는 머리에 문제가 있습니다. 정적 메서드는 결정적이어야합니다. 부작용이 없어야합니다.
David Arno

10

static클래스 의 한계에 대한 예를 들기 위해 일부 게이머가 다이 롤에 약간의 보너스를 원한다면 어떻게해야합니까? 그리고 그들은 큰 돈을 기꺼이 지불합니다! :-)

예, 다른 매개 변수를 추가 할 수 있습니다 Dice.roll(bonus).

나중에 D20이 필요합니다.

Dice.roll(bonus, sides)

예, 그러나 일부 플레이어는 "최고의 능력"을 발휘하여 결코 "떨림"을 할 수 없습니다 (롤 1).

Dice.roll(bonus, sides, isFumbleAllowed).

지저분 해지고 있지 않습니까?


이 질문에 직교 것으로 보인다 이러한 정적 방법 또는 정상적인 방법인지는 점점 지저분
JK.

4
@ jk, 나는 그의 요점을 이해했다고 생각합니다. 더 많은 유형의 오지에서 생각할 때 주사위 정적 클래스를 갖는 것은 의미가 없습니다. 이 경우 다른 OPS 객체를 가질 수 있으며 OOP 방식으로 모델링 할 수 있습니다.
Dherik

1
@TimothyTruckle 나는 논쟁의 여지가 없다. 내가 말하는 것은이 답변이 실제로 질문에 대답하지 않는다는 것입니다.
nvoigt

2
@nvoigt "저는 논쟁의 여지가 없습니다" -글쎄요. OO 언어의 가장 강력한 기능은 다형성 입니다. 그리고 정적 액세스 는 우리가 그것을 전혀 사용하지 못하게합니다. 그리고 당신은 맞아요 : new Dice().roll(...)의 concidered 수있다 정적 액세스 뿐만 아니라으로 Dice.roll(...). 우리는 그 의존성 을 주입 할 때만 혜택을 받습니다
Timothy Truckle

2
@jk 차이점은 모든 통화 static에서 혼란이 발생하고 모든 통화에서 필요한 지식이 필요하므로 응용 프로그램 전체에 전 세계적으로 뿌려집니다. OOP 구조에서는 생성자 / 팩토리 만 복잡 할 필요가 있으며 해당 다이의 세부 정보가 캡슐화됩니다. 그런 다음 다형성을 사용하고을 호출하십시오 roll(). 명확히하기 위해이 답변을 편집 할 수 있습니다.
user949300

3

Dice 클래스의 특정 경우 정적보다 인스턴스 메소드를 사용하면 테스트가 훨씬 쉬워 질 것이라고 생각합니다.

Dice 인스턴스 (예 : 게임 클래스)를 사용하는 무언가를 단위 테스트하려면 테스트에서 항상 고정 된 값의 시퀀스를 반환하는 Dice의 테스트 이중 형식을 삽입 할 수 있습니다. 당신의 테스트는 게임이 주사위 롤에 적합한 결과를 가지고 있는지 확인할 수 있습니다.

저는 Java 개발자는 아니지만 완전히 정적 인 Dice 클래스를 사용하는 것이 훨씬 어려울 것이라고 생각합니다. /programming/4482315/why-does-mockito-not-mock-static-methods를 참조 하십시오.


레코드의 경우 : Java에서는 바이트 코드를 조작하여 정적 종속성을 대체 할 PowerMock 이 있습니다. 그러나 그것을 사용하는 것은 나쁜 디자인에 대한 항복
일뿐입니다

0

이것은 실제로 모든 인스턴스 (및 "인스턴스 없음")가 상태를 공유 하는 Monostate 패턴 이라고합니다. 모든 멤버는 클래스 멤버입니다 (즉, 인스턴스 멤버가 아님). 그것들은 일반적으로 단일 책임 또는 요구 사항과 관련된 일련의 메소드와 상수를 묶는 툴킷 클래스를 구현하는 데 사용되지만 작동하기 위해 상태가 필요하지 않습니다 (순전히 기능적입니다). 실제로 Java에는 일부 번들이 번들로 제공됩니다 (예 : Math ).

약간의 주제를 벗어난 주제 : VisualBasic에서 키워드 이름 지정에 거의 동의하지 않지만이 경우 라이프 사이클 이후에 남아있는 것보다 shared분명히 명확하고 의미 적으로 더 우수 하다고 생각 합니다 (클래스 자체와 모든 인스턴스간에 공유 됨 ). static그것이 선언 된 범위의).

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