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