應用程式框架定義演算法骨架,將可變步驟延遲到子類別實作。本文示範以樣板方法模式建構可擴充的框架基底,包含初始化、執行、銷毀生命週期,並探討現代框架設計演進 (DI、中介軟體、選項模式)。
using System;
public abstract class ApplicationFramework
{
// 樣板方法:定義演算法骨架,不可被覆寫 (sealed)
public sealed void Run()
{
try
{
OnInitializing();
OnInitialized();
OnStarting();
OnRunning();
OnStopping();
}
finally
{
OnDisposing();
OnDisposed();
}
}
// 擴充點:受保護虛擬方法,子類別可選擇覆寫
protected virtual void OnInitializing() { }
protected virtual void OnInitialized() { }
protected virtual void OnStarting() { }
protected virtual void OnRunning() { } // 核心邏輯進入點
protected virtual void OnStopping() { }
protected virtual void OnDisposing() { }
protected virtual void OnDisposed() { }
}
public class MyBusinessApp : ApplicationFramework
{
private ILogger _logger;
private IConfiguration _config;
private IServiceProvider _services;
protected override void OnInitializing()
{
Console.WriteLine("[Framework] 初始化配置與服務容器...");
_config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
var services = new ServiceCollection();
ConfigureServices(services);
_services = services.BuildServiceProvider();
_logger = _services.GetRequiredService>();
}
protected override void OnInitialized()
{
_logger.LogInformation("服務容器建立完成");
}
protected override void OnStarting()
{
_logger.LogInformation("應用程式啟動中...");
// 啟動背景服務、連接資料庫、開啟網路埠等
}
protected override void OnRunning()
{
_logger.LogInformation("進入主迴圈...");
// 這裡可以是:
// - Console 選單迴圈
// - Windows Forms Application.Run()
// - ASP.NET Core WebApplication.Run()
// - gRPC 服務啟動
// 範例:簡單主迴圈
bool running = true;
while (running)
{
Console.Write("> ");
var input = Console.ReadLine();
if (input?.ToLower() == "exit") running = false;
else ProcessCommand(input);
}
}
protected override void OnStopping()
{
_logger.LogInformation("正在關閉...");
// 釋放資源、儲存狀態
}
protected override void OnDisposing()
{
(_services as IDisposable)?.Dispose();
}
private void ConfigureServices(IServiceCollection services)
{
services.AddLogging(b => b.AddConsole());
services.AddTransient();
// 註冊其他服務...
}
private void ProcessCommand(string cmd)
{
// 委派給服務處理
var svc = _services.GetRequiredService();
svc.Handle(cmd);
}
}
框架基底提供 IServiceProvider 存取,子類別在 OnInitializing 註冊服務,OnDisposing 釋放容器。
public class AppOptions
{
public string ConnectionString { get; set; }
public int MaxRetry { get; set; } = 3;
}
// 在 OnInitializing
services.Configure(_config.GetSection("App"));
// 使用
var options = _services.GetRequiredService>().Value;
public delegate Task MiddlewareDelegate(Context ctx, Func next);
public class PipelineFramework : ApplicationFramework
{
private readonly List _middlewares = new();
public void Use(MiddlewareDelegate middleware) => _middlewares.Add(middleware);
protected override void OnRunning()
{
var context = new Context();
var pipeline = BuildPipeline();
pipeline(context).Wait();
}
private Func BuildPipeline()
{
Func end = ctx => Task.CompletedTask;
for (int i = _middlewares.Count - 1; i >= 0; i--)
{
var next = end;
var mw = _middlewares[i];
end = ctx => mw(ctx, next);
}
return end;
}
}
// 使用
var app = new PipelineFramework();
app.Use(async (ctx, next) => { Console.WriteLine("Middleware 1 前"); await next(); Console.WriteLine("Middleware 1 後"); });
app.Use(async (ctx, next) => { Console.WriteLine("Middleware 2 前"); await next(); Console.WriteLine("Middleware 2 後"); });
app.Run();
protected override void OnInitializing()
{
base.OnInitializing();
LoadPlugins();
}
private void LoadPlugins()
{
var pluginDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins");
foreach (var dll in Directory.GetFiles(pluginDir, "*.dll"))
{
var asm = Assembly.LoadFrom(dll);
foreach (var type in asm.GetTypes())
{
if (typeof(IModule).IsAssignableFrom(type) && !type.IsAbstract)
{
var module = (IModule)Activator.CreateInstance(type);
module.Initialize(_services);
_modules.Add(module);
}
}
}
}
實際專案建議直接使用 .NET 內建 IHost,已實作完整生命週期、DI、配置、日誌、優雅關閉:
using Microsoft.Extensions.Hosting;
public class Program
{
public static async Task Main(string[] args)
{
var host = Host.CreateDefaultBuilder(args)
.ConfigureServices((ctx, services) =>
{
services.AddHostedService();
services.AddTransient();
})
.Build();
await host.RunAsync(); // 封裝了完整生命週期
}
}
public class WorkerService : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
// 背景工作
await Task.Delay(1000, stoppingToken);
}
}
}
樣板方法模式提供框架的基本骨架:定義流程、延遲實作。關鍵點:
sealed 防止破壞流程protected virtual,預設空實作Microsoft.Extensions.Hosting (Generic Host)良好的框架設計能強制統一架構、降低樣板代碼、提升團隊開發效率。