一些可重用代码的体系结构

时间:2009-07-04 16:03:03

标签: oop architecture code-reuse library-design

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

3 个答案:

答案 0 :(得分:4)

我总是喜欢通过合成(你的第二个选项)而不是继承(你的第一个选项)来重复使用。

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

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

这允许每个应用程序重用与您的特定应用程序相关的框架部分,而不必被迫采取一切措施,允许单个应用程序更自由。如果将来某些应用程序不完全符合您今天所考虑的结构,那么通过继承重用有时会变得非常严格。

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

答案 1 :(得分:0)

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

因此,您的客户端只需实现一个接口,例如(在Java中)

public interface ClientCode {

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

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

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

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

答案 2 :(得分: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();
}