문제

공통 구조를 공유하고 동일한 방법 (예 : 로깅, 데이터베이스 연결 설정, 환경 설정)으로 동일한 작업을 수행 해야하는 여러 개의 작고 간단한 응용 프로그램을 작성하고 있으며 재사용 가능한 구성 요소. 이 코드는 강력하고 정적으로 입력 한 언어로 작성되었습니다 (예 : Java 또는 C#,이 문제를 둘 다를 해결해야했습니다). 현재 나는 이것을 얻었다 :

abstract class EmptyApp //this is the reusable bit
{
   //various useful fields: loggers, db connections

   abstract function body()
   function run()
   {
        //do setup
        this.body()
        //do cleanup
   }
}

class theApp extends EmptyApp //this is a given app
{
   function body()
   {
        //do stuff using some fields from EmptyApp
   }

   function main()
   {
        theApp app = new theApp()
        app.run()
   }
 }

더 좋은 방법이 있습니까? 아마도 다음과 같이? 상충 관계를 평가하는 데 어려움이 있습니다 ...

abstract class EmptyApp
{
     //various fields
}

class ReusableBits
{
    static function doSetup(EmptyApp theApp)

    static function doCleanup(EmptyApp theApp)
}

class theApp extends EmptyApp
{
    function main()
    {
         ReusableBits.doSetup(this);
         //do stuff using some fields from EmptyApp
         ReusableBits.doCleanup(this);
    }
}

명백한 트레이드 오프 중 하나는 옵션 2를 사용하면 '프레임 워크'가 앱을 트리 캐치 블록으로 랩핑 할 수 없다는 것입니다 ...

도움이 되었습니까?

해결책

나는 상속 (첫 번째 옵션)이 아닌 구성 (두 번째 옵션)을 통해 재사용을 항상 선호했습니다.

상속은 코드 재사용보다는 클래스 사이에 관계가있을 때만 사용해야합니다.

따라서 귀하의 예제에 대해 각 응용 프로그램이 AS/필요한 경우 각 응용 프로그램을 수행하는 1 일을 수행하는 여러 개의 재사용 가능한 클래스가 있습니다.

이를 통해 각 응용 프로그램은 모든 응용 프로그램과 관련된 프레임 워크의 일부를 재사용 할 수있게 해주 며, 모든 응용 프로그램과 관련된 모든 것을 취해야하지 않고 개별 애플리케이션이 더 많은 자유를 얻을 수 있습니다. 상속을 통해 재사용하는 것은 미래에 오늘날 당신이 염두에두고있는 구조에 정확하게 맞지 않는 일부 응용 프로그램이 있으면 때때로 매우 제한적이 될 수 있습니다.

또한 프레임 워크를 별도의 유틸리티로 나누면 단위 테스트 및 테스트 중심 개발 개발이 훨씬 쉽습니다.

다른 팁

사용자 정의 가능한 코드로 프레임 워크를 호출하지 않겠습니까? 따라서 클라이언트는 객체를 생성하여 프레임 워크에 주입합니다. 프레임 워크는 초기화, 호출 setup() 등. 그런 다음 고객의 코드를 호출합니다. 완료되면 (또는 예외가 발생한 후에도) 프레임 워크가 cleanup() 그리고 출구.

따라서 고객은 단순히 (Java)와 같은 인터페이스를 구현합니다.

public interface ClientCode {

    void runClientStuff(); // for the sake of argument
}

프레임 워크 코드는이 구현으로 구성되며 호출 runClientStuff() 필요할 때마다.

그래서 당신은 그렇지 않습니다 파생 응용 프로그램 프레임 워크에서 단순히 특정 계약을 준수하는 클래스를 제공합니다. 앱에서 파생되지 않기 때문에 런타임 (예 : 클라이언트가 앱에 제공 할 클래스)에서 응용 프로그램 설정을 구성 할 수 있으므로 종속성이 정적이지 않기 때문입니다.

위의 인터페이스는 여러 가지 방법을 갖도록 확장 될 수 있으며, 응용 프로그램은 라이프 사이클의 다른 단계에서 필요한 방법을 호출 할 수 있지만 (예 : 클라이언트 별 설정/정리를 제공하기 위해) 기능이 기능의 예입니다.

상속은 코드 듀오를 유사하게 재사용하는 모든 객체가 유사점으로 재사용되는 경우에만 좋은 선택 일뿐입니다. 또는 발신자가 동일한 핵분열에서 발신자와 상호 작용할 수 있기를 원한다면. 내가 방금 언급 한 것이 당신에게 적용된다면 내 경험을 바탕으로 당신의 기본/추상 클래스에 일반적인 논리를 갖는 것이 항상 좋습니다.

이것이 C#에서 샘플 앱을 다시 작성하는 방법입니다.

abstract class BaseClass
{
    string field1 = "Hello World";
    string field2 = "Goodbye World";

    public void Start()
    {
        Console.WriteLine("Starting.");
        Setup();
        CustomWork();
        Cleanup();
    }

    public virtual void Setup()
    {Console.WriteLine("Doing Base Setup.");}

    public virtual void Cleanup()
    {Console.WriteLine("Doing Base Cleanup.");}

    public abstract void CustomWork();
}

class MyClass : BaseClass
{
    public override void CustomWork()
    {Console.WriteLine("Doing Custome work.");}

    public override void Cleanup()
    {
        Console.WriteLine("Doing Custom Cleanup");
        //You can skip the next line if you want to replace the
        //cleanup code rather than extending it
        base.Cleanup();
    }

}

void Main()
{
    MyClass worker = new MyClass();
    worker.Start();
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top