태그 보관물: object-oriented-design

object-oriented-design

단일 (공용) 메소드 만있는 클래스가 문제입니까? 스프라이트로 저장하여 작동합니다. 최근에 저는 프로젝트를 위해

현재 비디오 감시 영상에서 압축 및 색인 생성을 수행하는 소프트웨어 프로젝트를 진행 중입니다. 압축은 배경 및 전경 개체를 분할 한 다음 배경을 정적 이미지로 저장하고 전경을 스프라이트로 저장하여 작동합니다.

최근에 저는 프로젝트를 위해 디자인 한 클래스 중 일부를 검토하기 시작했습니다.

공용 메소드가 하나 뿐인 많은 클래스가 있음을 알았습니다. 이 수업 중 일부는 다음과 같습니다.

  • VideoCompressor ( compress유형의 입력 비디오를 가져 와서 유형 RawVideo의 출력 비디오를 반환하는 메서드 사용 CompressedVideo)
  • VideoSplitter ( split유형의 입력 비디오를 가져 와서 RawVideo각 유형의 출력 비디오 2 개로 구성된 벡터를 반환 하는 메서드 사용 RawVideo)
  • VideoIndexer ( index유형의 입력 비디오를 가져 와서 유형 RawVideo의 비디오 인덱스를 반환 하는 메서드 사용 VideoIndex)

나는 나 자신을 그냥 같은 통화를 할 수 각 클래스의 인스턴스를 찾을 수 있습니다 VideoCompressor.compress(...), VideoSplitter.split(...), VideoIndexer.index(...).

표면적으로 클래스 이름은 의도 된 기능을 충분히 설명하고 있으며 실제로는 명사라고 생각합니다. 이에 따라, 그들의 방법도 동사입니다.

이것이 실제로 문제입니까?



답변

아니, 이것은 문제가 아니며, 그 반대입니다. 그것은 모듈성의 표시이며 클래스의 명확한 책임입니다. 희박한 인터페이스는 해당 클래스의 사용자 관점에서 파악하기 쉽고 느슨한 결합을 권장합니다. 이것은 많은 장점이 있지만 단점은 거의 없습니다. 더 많은 구성 요소가 그런 식으로 설계되기를 바랍니다!


답변

더 이상 객체 지향이 아닙니다. 이러한 클래스는 아무 것도 나타내지 않기 때문에 함수의 그릇 일뿐입니다.

그렇다고 잘못되었다는 의미는 아닙니다. 기능이 충분히 복잡하거나 일반적인 경우 (즉, 인수가 구체적인 최종 유형이 아닌 인터페이스 인 경우) 해당 기능을 별도의 모듈 에 넣는 것이 좋습니다 .

거기에서 그것은 당신의 언어에 달려 있습니다. 언어에 무료 기능이있는 경우 기능을 내보내는 모듈이어야합니다. 왜 수업이 아닌 척하는 이유. 언어에 Java와 같은 무료 기능이없는 경우 단일 공용 메소드를 사용하여 클래스를 작성하십시오. 글쎄, 그것은 단지 객체 지향 디자인의 한계를 보여줍니다. 때로는 기능성이 단순히 더 잘 맞습니다.

단일 공용 메서드로 인터페이스를 구현해야하기 때문에 단일 공용 메서드가있는 클래스가 필요할 수 있습니다. 관찰자 패턴이나 의존성 주입 또는 무엇이든 사용하십시오. 다시 언어에 따라 다릅니다. 퍼스트 클래스 functor (C ++ ( std::function또는 템플릿 매개 변수), C # (delegate), Python, Perl, Ruby ( proc), Lisp, Haskell 등)가있는 언어에서 이러한 패턴은 함수 유형을 사용하며 클래스가 필요하지 않습니다. Java에는 아직 버전 8의 함수 유형이 없으므로 단일 메소드 인터페이스와 해당 단일 메소드 클래스를 사용합니다.

물론 하나의 거대한 함수 작성을 옹호하지는 않습니다. 개인 서브 루틴이 있어야하지만 구현 파일 (C ++의 파일 레벨 정적 또는 익명 네임 스페이스) 또는 공용 함수 내에서만 인스턴스화되는 개인 헬퍼 클래스 ( 데이터 저장 여부)에 대해 개인용 일 수 있습니다.


답변

지정된 메소드를 전용 클래스로 추출해야하는 이유가있을 수 있습니다. 이러한 이유 중 하나는 Dependency Injection을 허용하는 것입니다.

VideoExporter결국 비디오를 압축 할 수 있는 클래스가 있다고 상상해보십시오 . 깨끗한 방법은 인터페이스를 갖는 것입니다.

interface IVideoCompressor
{
    Stream compress(Video video);
}

다음과 같이 구현됩니다.

class MpegVideoCompressor : IVideoCompressor
{
    // ...
}

class FlashVideoCompressor : IVideoCompressor
{
    // ...
}

그리고 이런 식으로 사용 :

class VideoExporter
{
    // ...
    void export(Destination destination, IVideoCompressor compressor)
    {
        // ...
        destination = compressor(this.source);
        // ...
    }
    // ...
}

나쁜 대안은해야하는 것 VideoExporter로터리 압축기의 압축을 포함한 모든 작업을, 공공 방법을 많이 가지고 있으며 않는합니다. 그것은 유지 보수의 악몽이되어 다른 비디오 형식에 대한 지원을 추가하기가 어려워졌습니다.


답변

이것은 함수를 다른 함수에 인수로 전달하려는 표시입니다. 귀하의 언어 (Java?)가 지원하지 않는 것 같습니다. 그럴 경우, 선택한 언어가 부족하기 때문에 디자인면에서 그다지 실패하지 않습니다. 이것은 모든 것이 클래스 여야한다고 주장하는 언어의 가장 큰 문제 중 하나입니다.

실제로 이러한 가짜 기능을 전달하지 않으면 자유 / 정적 기능이 필요합니다.


답변

나는 파티에 늦었다는 것을 알고 있지만 모든 사람들이 이것을 지적하기 위해 놓친 것 같습니다.

이것은 Strategy Pattern 이라는 잘 알려진 디자인 패턴 입니다.

하위 패턴을 해결하기 위해 여러 가지 가능한 전략이있을 때 전략 패턴이 사용됩니다. 일반적으로 모든 구현에 대해 계약을 시행하는 인터페이스를 정의한 다음 특정 형태의 종속성 주입 을 사용하여 구체적인 전략을 제공합니다.

이 경우 예를 들어, 당신은 할 수 interface VideoCompressor후 예를 들어, 여러 다른 구현이 class H264Compressor implements VideoCompressorclass XVidCompressor implements VideoCompressor. OP가 없으면 인터페이스가 포함되어 있다고해도 명확하지는 않지만, 필요한 경우 전략 작성자가 전략 패턴을 구현하기 위해 문을 열어 두었을 수도 있습니다. 어느 쪽 자체도 좋은 디자인입니다.

OP가 지속적으로 메서드를 호출하기 위해 클래스를 인스턴스화하는 문제는 종속성 주입과 전략 패턴을 올바르게 사용하지 않는 문제입니다. 포함하는 클래스에는 필요한 곳에서 인스턴스화하는 대신 전략 개체가있는 멤버가 있어야합니다. 그리고이 멤버는 예를 들어 생성자에 주입되어야합니다.

대부분의 경우 전략 패턴은 단일 doStuff(...)메소드 만으로 인터페이스 클래스 (표시 한대로)를 생성 합니다.


답변

public interface IVideoProcessor
{
   void Split();

   void Compress();

   void Index();
}

당신이 가진 것은 모듈 식이며 훌륭하지만, 이러한 책임을 IVideoProcessor로 그룹화한다면 DDD 관점에서 더 의미가 있습니다.

반면에 분할, 압축 및 인덱싱이 어떤 식 으로든 관련이 없다면 별도의 구성 요소로 유지하는 것보다 그렇습니다.


답변

문제는 데이터가 아니라 디자인의 기능적 측면에서 작업하는 것입니다. 실제로 가지고있는 것은 OO 화 된 3 개의 독립형 기능입니다.

예를 들어 VideoCompressor 클래스가 있습니다. 비디오를 압축하도록 설계된 클래스로 작업하는 이유-이 유형의 각 객체에 포함 된 (비디오) 데이터를 압축하기위한 메소드가있는 Video 클래스가없는 이유는 무엇입니까?

OO 시스템을 설계 할 때 적용 할 수있는 활동을 나타내는 클래스가 아니라 객체를 나타내는 클래스를 만드는 것이 가장 좋습니다. 이전에는 클래스를 유형이라고했습니다. OO는 새로운 데이터 유형을 지원하여 언어를 확장하는 방법이었습니다. OO를 이와 같이 생각하면 클래스를 더 잘 디자인 할 수 있습니다.

편집하다:

concat 메소드가있는 문자열 클래스를 상상해보십시오. 클래스에서 인스턴스화 된 각 객체에 문자열 데이터가 포함 된 것을 구현할 수 있습니다.

string mystring("Hello");
mystring.concat("World");

그러나 OP는 다음과 같이 작동하기를 원합니다.

string mystring();
string result = mystring.concat("Hello", "World");

이제 클래스를 사용하여 관련 함수 모음을 보유 할 수있는 곳이 있지만 OO가 아닙니다. 코드베이스를 더 잘 관리하기 위해 언어의 OO 기능을 사용하는 편리한 방법이지만 어떤 방식도 아닙니다 “OO 디자인”. 이러한 경우의 객체는 완전히 인공적이며 언어는 이러한 종류의 문제를 관리하는 데 더 좋은 것을 제공하지 않기 때문에 이와 같이 간단하게 사용됩니다. 예. C #과 같은 언어에서는 정적 클래스를 사용하여이 기능을 제공합니다. 클래스 메커니즘을 재사용하지만 더 이상 메소드를 호출하기 위해 오브젝트를 인스턴스화 할 필요는 없습니다. 당신은에 string.IsNullOrEmpty(mystring)비해 가난한 것 같은 방법으로 끝납니다 mystring.isNullOrEmpty().

따라서 누군가 “클래스를 어떻게 디자인합니까?”라고 물으면 클래스에 포함 된 함수보다는 클래스에 포함될 데이터를 생각하는 것이 좋습니다. “클래스는 클래스가 많다”고하면 “더 나은 C”스타일 코드를 작성하게됩니다. (C 코드를 개선하는 경우 반드시 나쁜 것은 아니지만) 최고의 OO 설계 프로그램을 제공하지는 않습니다.