크고 밀접하게 연결된 클래스를 나누는 방법은 무엇입니까?


14

가능하면 가볍고 깨끗한 디자인을 위해 리팩토링하고 싶은 2k 라인 이상의 코드 클래스가 있습니다.

너무 큰 이유는 이러한 클래스가 대부분의 메소드가 액세스해야하는 맵 세트를 처리하고 메소드가 서로 매우 연결되어 있기 때문입니다.

매우 구체적인 예 Server를 들겠습니다. 들어오는 메시지를 처리 하는 클래스가 있습니다 . 이 같은 방법이있다 joinChatroom, searchUsers, sendPrivateMessage, 이러한 방법 등 모든이 (가) 매핑 조작 등 users, chatrooms, servers, ...

채팅방과 관련된 메시지를 처리하는 클래스, 사용자에 대한 모든 처리 등을 할 수 있다면 좋을 것입니다. 그러나 여기서 가장 큰 문제는 대부분의 방법에서 모든 맵을 사용해야한다는 것입니다. 그렇기 때문에 지금은 모두 Server공통지도에 의존하고 방법이 서로 밀접하게 연결되어 있기 때문에 모두 수업에 집중하고 있습니다.

Chatrooms 클래스를 만들어야하지만 다른 각 객체에 대한 참조가 필요합니다. 다른 모든 객체 등을 참조하는 클래스 사용자

나는 뭔가 잘못하고 있다고 생각합니다.


User 및 Chatroom과 같은 클래스를 만들려면 이러한 클래스에 공통 데이터 구조에 대한 참조 만 필요합니까 아니면 서로 참조해야합니까?

여기에 몇 가지 만족스러운 답변이 있습니다. 하나를 선택해야합니다.
jeremyjjbrown

@jeremyjjbrown 질문이 옮겨졌고 그것을 잃었습니다. 답변을 선택했습니다.
Matthew

답변:


10

당신의 설명에서, 나는 당신의지도가 순수한 데이터 가방이며 Server방법의 모든 논리를 가지고 있다고 생각합니다 . 모든 대화방 논리를 별도의 클래스로 푸시하면 데이터가 포함 된 맵이 계속 유지됩니다.

대신 개별 대화방, 사용자 등을 개체로 모델링하십시오. 그렇게하면 거대한 데이터 맵 대신 특정 방법에 필요한 특정 객체 만 전달할 수 있습니다.

예를 들면 다음과 같습니다.

public class User {
  private String name;
  ...

  public void sendMessage(String message) {
    ...
  }
}

public class Chatroom {
  // users in this chatroom
  private Collection<User> users;

  public void add(User user) {
    users.add(user);
  }

  public void sendMessage(String msg) {
    for (User user : users)
      user.sendMessage(msg);
  }
}

public class Server {
  // all users on the server
  private Collection<User> users;

  // all chatrooms on the server
  private Collection<Chatroom> chatrooms;

  /* methods to handle incoming messages */
}

이제 메시지를 처리하기 위해 몇 가지 특정 메소드를 쉽게 호출 할 수 있습니다.

대화방에 참여하고 싶습니까?

chatroom.add(user);

비공개 메시지를 보내시겠습니까?

user.sendMessage(msg);

공개 메시지를 보내시겠습니까?

chatroom.sendMessage(msg);

5

각 컬렉션을 보유하는 클래스를 만들 수 있어야합니다. Server이러한 각 컬렉션에 대한 참조가 필요 하지만 기본 컬렉션에 액세스하거나 유지 관리하지 않는 최소한의 논리 만 필요합니다. 이를 통해 서버가 수행하는 작업을보다 명확하게 파악하고 서버의 작동 방식을 분리 할 수 ​​있습니다.


4

이와 같은 큰 수업을 보았을 때 나 가려고하는 수업이 종종 있다는 것을 알았습니다. 이 클래스와 관련이 없다고 생각되는 메소드를 알고 있다면 정적으로 만드십시오. 그런 다음 컴파일러는이 메소드가 호출하는 다른 메소드를 알려줍니다. 자바도 역시 정적이라고 주장 할 것이다. 당신은 그것들을 정적으로 만듭니다. 다시 컴파일러는 호출하는 메소드를 알려줍니다. 더 이상 컴파일 실패가 없을 때까지이 작업을 계속 반복합니다. 그런 다음 큰 클래스에 많은 정적 메소드가 있습니다. 이제 이것을 새로운 클래스로 끌어 내고 메소드를 정적이 아닌 것으로 만들 수 있습니다. 그런 다음 원래 큰 클래스에서이 새 클래스를 호출 할 수 있습니다.

그런 다음 클래스 디자인에 만족할 때까지 프로세스를 반복 할 수 있습니다.

Martin Fowler의 책은 정말 잘 읽었 으므로이 정적 트릭을 사용할 수없는 시간이 있기 때문에 이것을 추천합니다.


1
이 Martin Fowler의 책 martinfowler.com/books/refactoring.html
Arul

1

대부분의 코드가 존재하기 때문에 도우미 클래스를 사용하여 메소드를 옮기는 것이 좋습니다. 쉽게 리팩토링 할 수 있습니다. 따라서 서버 클래스에는 여전히 맵이 포함됩니다. 그러나 join (Map chatrooms, String user), List getUsers (Map chatrooms), Map getChatrooms (String user)와 같은 메소드를 사용하여 도우미 클래스 인 ChatroomHelper를 사용합니다.

서버 클래스는 ChatroomHelper, UserHelper 등의 인스턴스를 보유하므로 메소드를 논리적 헬퍼 클래스로 이동합니다. 이것으로 공개 메소드를 서버에 그대로 둘 수 있으므로 모든 호출자를 변경할 필요가 없습니다.


1

추가하려면 casablanca의 통찰력있는 답변에 -여러 클래스가 특정 유형의 엔티티 (컬렉션에 사용자 추가, 메시지 처리 등)로 동일한 기본 작업을 수행 해야하는 경우 해당 프로세스도 별도로 유지해야합니다.

상속 또는 구성에 의해 여러 가지 방법이 있습니다. 상속을 위해 필드 나 기능을 제공하여 사용자 또는 메시지를 처리 chatroom하고 user해당 클래스를 좋아 하거나 확장하는 엔티티를 갖는 구체적인 메소드와 함께 추상 기본 클래스를 사용할 수 있습니다 .

여러 가지 이유로 상속보다 구성을 사용하는 것이 일반적으로 좋은 규칙입니다. 컴포지션을 사용하여 다양한 방법으로이 작업을 수행 할 수 있습니다. 사용자 또는 메시지를 처리하는 것은 클래스의 책임에 중요한 기능이므로 생성자 삽입이 가장 적합하다고 주장 할 수 있습니다. 이렇게하면 종속성이 투명 해지며 필요한 기능없이 개체를 만들 수 없습니다. 사용자 또는 메시지를 처리하는 방식이 변경되거나 확장 될 수있는 경우 전략 패턴 과 같은 것을 사용하는 것이 좋습니다.

두 경우 모두 유연성을 위해 구체적인 클래스가 아닌 인터페이스를 향해 코딩해야합니다.

그러나 이러한 패턴을 사용할 때는 항상 복잡성을 추가하는 비용을 고려하십시오. 필요하지 않은 경우 코딩하지 마십시오. 사용자 / 메시지 처리 방식을 변경하지 않을 것임을 알고 있다면 전략 패턴의 구조적 복잡성이 필요하지 않지만 우려를 분리하고 반복을 피하려면 여전히 일반적인 기능과 이혼해야합니다 그것을 사용하는 구체적인 사례에서-그 반대의 우선적 인 이유가 없다면, 그러한 취급 기능 사용자 (채팅룸, 사용자)를 취급하는 객체로 구성하십시오.

요약하자면 다음과 같습니다.

  1. casablanca가 썼 듯이 : 채팅방, 사용자 등을 분리하고 캡슐화하십시오.
  2. 별도의 공통 기능
  3. 데이터 표현 (접근 및 돌연변이뿐만 아니라)과 데이터의 개별 인스턴스 또는 그 집합에 대한보다 복잡한 기능 (예 searchUsers: 컬렉션 클래스 또는 저장소 / 아이덴티티 맵 과 같은 것)과 이혼하기 위해 개별 기능을 분리하는 것을 고려하십시오. )

0

문제에 대한 완전한 설명이 없으므로 지식이 거의없는 훌륭한 디자인을 제공하는 것이 불가능하기 때문에 귀하의 질문에 대한 답변이 너무 일반적이라고 생각합니다. 예를 들어, 더 나은 디자인의 가능한 유용성에 대한 귀하의 우려 중 하나를 해결할 수 있습니다.

서버 클래스와 향후 Chatroom 클래스는 사용자에 대한 데이터를 공유하지만이 데이터는 달라야합니다. 서버에는 아마도 사용자 세트가 연결되어 있고, 서버 자체에 속하는 Chatroom은 현재 특정 Chatroom에 로그인 한 사용자와 다른 사용자 세트 (첫 번째 세트의 하위 세트)를 가지고 있습니다.

데이터 유형이 동일하더라도 동일한 정보가 아닙니다.
좋은 디자인에는 많은 장점이 있습니다.

나는 Fowler가 언급 한 책을 읽지 못했지만 Folwer가 다른 것을 읽었으며 신뢰하는 사람들이 나에게 추천 했으므로 다른 사람들과 합의하기에 충분히 편안합니다.


0

지도에 액세스 할 필요가 메가 클래스를 정당화하지는 않습니다. 여러 클래스에서 논리를 분리해야하며 각 클래스에는 getMap 메소드가 있어야 다른 클래스가 맵에 액세스 할 수 있습니다.



-1

소프트웨어 메트릭 측면에서 큰 클래스는 백입니다. 이 진술을 입증하는 무제한 논문이 있습니다. 왜 그런 겁니까 ? 큰 클래스는 작은 클래스보다 이해하기 어렵고 수정하는 데 더 많은 시간이 필요하기 때문입니다. 또한 큰 클래스는 테스트 할 때 매우 어렵습니다. 큰 클래스는 원하지 않는 것들이 포함되어 있기 때문에 재사용하려는 경우 매우 어렵습니다.

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