2

我正在编写一些小型、简单的应用程序,它们共享一个共同的结构,并且需要以相同的方式做一些相同的事情(例如日志记录、数据库连接设置、环境设置),我正在寻找一些关于构建可重复使用的组件。代码是用强类型和静态类型的语言编写的(例如 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,“框架”无法将应用程序包装在 try-catch 块中......

4

3 回答 3

4

我一直倾向于通过组合重用(您的第二个选项)而不是继承(您的第一个选项)。

仅当类之间存在关系而不是代码重用时才应使用继承。

因此,对于您的示例,我将有多个 ReusableBits 类,每个类都做一件事情,每个应用程序在需要时使用。

这允许每个应用程序重新使用与该特定应用程序相关的框架部分,而不必被迫采取一切措施,从而为各个应用程序提供更多自由。如果您将来有一些应用程序不完全适合您今天所考虑的结构,那么通过继承重用有时会变得非常有限制。

如果您将框架分解为单独的实用程序,您还会发现单元测试和测试驱动开发更容易。

于 2009-07-04T16:39:07.457 回答
0

为什么不让框架调用您的可定制代码呢?因此,您的客户创建了一些对象,并将其注入到框架中。框架初始化、调用setup()等,然后调用您客户的代码。完成后(甚至在抛出异常之后),框架然后调用cleanup()并退出。

因此,您的客户端将简单地实现一个接口,例如(在 Java 中)

public interface ClientCode {

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

并且框架代码配置了这个的实现,并runClientStuff()在需要时调用。

因此,您不必从应用程序框架派生,而只是提供一个符合特定约定的类。您可以在运行时配置应用程序设置(例如客户端将向应用程序提供什么类),因为您不是从应用程序派生的,因此您的依赖关系不是静态的。

上面的接口可以扩展为具有多个方法,并且应用程序可以在生命周期的不同阶段调用所需的方法(例如,提供特定于客户端的设置/清理),但这是功能蠕变的一个示例 :-)

于 2009-07-04T16:06:45.197 回答
0

请记住,如果所有继承的对象都重用代码,因为它们的相似之处,继承才是一个不错的选择。或者如果您希望调用者能够在同一个裂变中与他们交互。如果我刚才提到的适用于您,那么根据我的经验,在您的基础/抽象类中拥有通用逻辑总是更好。

这就是我将如何用 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();
}
于 2009-07-04T16:29:10.097 回答