|
4 | 4 | namespace SharpFM.Model.ClipTypes; |
5 | 5 |
|
6 | 6 | /// <summary> |
7 | | -/// Static, explicitly-populated registry of <see cref="IClipTypeStrategy"/> |
8 | | -/// implementations keyed by <c>Mac-XM*</c> format id. Built-in strategies are |
9 | | -/// registered once at startup via <see cref="RegisterBuiltIns"/>; tests |
10 | | -/// reset and re-register through <see cref="Reset"/>. |
| 7 | +/// Compile-time registry of <see cref="IClipTypeStrategy"/> implementations |
| 8 | +/// keyed by <c>Mac-XM*</c> format id. Strategies are fully owned by SharpFM |
| 9 | +/// (no plugin extension point), so the table is built once from a static |
| 10 | +/// list and is read-only thereafter — no locks, no bootstrap, no reset. |
| 11 | +/// Adding a new clip type means writing the strategy and adding it to |
| 12 | +/// <see cref="BuiltIns"/>. |
11 | 13 | /// </summary> |
12 | | -/// <remarks> |
13 | | -/// Reflection-based auto-discovery (the pattern used by <c>StepRegistry</c>) |
14 | | -/// is deliberately not used here — clip types are few, low-cardinality, and |
15 | | -/// explicit registration makes the bootstrapping order obvious. |
16 | | -/// </remarks> |
17 | 14 | public static class ClipTypeRegistry |
18 | 15 | { |
19 | | - private static readonly object _gate = new(); |
20 | | - private static readonly Dictionary<string, IClipTypeStrategy> _strategies = new(); |
| 16 | + public static IReadOnlyList<IClipTypeStrategy> BuiltIns { get; } = |
| 17 | + [ |
| 18 | + ScriptClipStrategy.Steps, |
| 19 | + ScriptClipStrategy.Script, |
| 20 | + TableClipStrategy.Table, |
| 21 | + TableClipStrategy.Field, |
| 22 | + LayoutClipStrategy.Instance, |
| 23 | + ]; |
21 | 24 |
|
22 | | - /// <summary>Register a strategy. A duplicate <see cref="IClipTypeStrategy.FormatId"/> overwrites the prior entry.</summary> |
23 | | - public static void Register(IClipTypeStrategy strategy) |
24 | | - { |
25 | | - lock (_gate) |
26 | | - { |
27 | | - _strategies[strategy.FormatId] = strategy; |
28 | | - } |
29 | | - } |
| 25 | + private static readonly Dictionary<string, IClipTypeStrategy> _byFormatId = |
| 26 | + BuiltIns.ToDictionary(s => s.FormatId); |
| 27 | + |
| 28 | + /// <summary>All built-in strategies (excludes the opaque fallback).</summary> |
| 29 | + public static IReadOnlyList<IClipTypeStrategy> All => BuiltIns; |
30 | 30 |
|
31 | 31 | /// <summary> |
32 | 32 | /// Resolve a strategy for the given format id. Unknown ids fall back to |
33 | 33 | /// <see cref="OpaqueClipStrategy.Instance"/> so callers always receive a |
34 | 34 | /// usable strategy. |
35 | 35 | /// </summary> |
36 | | - public static IClipTypeStrategy For(string formatId) |
37 | | - { |
38 | | - lock (_gate) |
39 | | - { |
40 | | - return _strategies.TryGetValue(formatId, out var strategy) |
41 | | - ? strategy |
42 | | - : OpaqueClipStrategy.Instance; |
43 | | - } |
44 | | - } |
45 | | - |
46 | | - /// <summary>True if the given format id has a dedicated strategy registered.</summary> |
47 | | - public static bool IsRegistered(string formatId) |
48 | | - { |
49 | | - lock (_gate) |
50 | | - { |
51 | | - return _strategies.ContainsKey(formatId); |
52 | | - } |
53 | | - } |
54 | | - |
55 | | - /// <summary>All explicitly-registered strategies, in registration order.</summary> |
56 | | - public static IReadOnlyList<IClipTypeStrategy> All |
57 | | - { |
58 | | - get |
59 | | - { |
60 | | - lock (_gate) |
61 | | - { |
62 | | - return _strategies.Values.ToList(); |
63 | | - } |
64 | | - } |
65 | | - } |
66 | | - |
67 | | - /// <summary> |
68 | | - /// Register every built-in clip-type strategy. Called once at host startup; |
69 | | - /// idempotent thanks to <see cref="Register"/>'s overwrite semantics. Adding |
70 | | - /// a new <c>Mac-XM*</c> format is a single additional <see cref="Register"/> |
71 | | - /// call here. Opaque is the implicit fallback and is not registered. |
72 | | - /// </summary> |
73 | | - public static void RegisterBuiltIns() |
74 | | - { |
75 | | - Register(ScriptClipStrategy.Steps); |
76 | | - Register(ScriptClipStrategy.Script); |
77 | | - Register(TableClipStrategy.Table); |
78 | | - Register(TableClipStrategy.Field); |
79 | | - Register(LayoutClipStrategy.Instance); |
80 | | - } |
81 | | - |
82 | | - /// <summary>Clear the registry. Tests use this to isolate from production registrations.</summary> |
83 | | - internal static void Reset() |
84 | | - { |
85 | | - lock (_gate) |
86 | | - { |
87 | | - _strategies.Clear(); |
88 | | - } |
89 | | - } |
| 36 | + public static IClipTypeStrategy For(string formatId) => |
| 37 | + _byFormatId.TryGetValue(formatId, out var strategy) |
| 38 | + ? strategy |
| 39 | + : OpaqueClipStrategy.Instance; |
| 40 | + |
| 41 | + /// <summary>True if the given format id has a dedicated built-in strategy.</summary> |
| 42 | + public static bool IsRegistered(string formatId) => |
| 43 | + _byFormatId.ContainsKey(formatId); |
90 | 44 | } |
0 commit comments