Browse Source

Implement Cascade Builder Pattern

0x0001F36D 5 years ago
parent
commit
086f598f49

+ 1 - 1
Yuuna.sln

@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio Version 16
 VisualStudioVersion = 16.0.29503.13
 MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yuuna.Contracts", "src\Yuuna.Contracts\Yuuna.Contracts.csproj", "{9063A9AB-AD78-49F4-9B59-192CAC7A798A}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yuuna.Contracts", "src\Yuuna.Contracts\Yuuna.Contracts.csproj", "{9063A9AB-AD78-49F4-9B59-192CAC7A798A}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution

+ 1 - 1
src/Yuuna.Contracts/GroupManager.cs

@@ -19,7 +19,7 @@
 
             [DebuggerNonUserCode]
             [MethodImpl(MethodImplOptions.AggressiveInlining)]
-            internal static void ValidateGroupKey(string key)
+            private static void ValidateGroupKey(string key)
             {
                 if (string.IsNullOrWhiteSpace(key))
                     throw new ArgumentNullException(nameof(key));

+ 15 - 0
src/Yuuna.Contracts/Logging/IHistorian.cs

@@ -0,0 +1,15 @@
+
+namespace Yuuna.Contracts.Logging
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Text;
+
+    /// <summary>
+    /// 用來記錄資訊及錯誤的歷史學家。
+    /// </summary>
+    public interface IHistorian
+    {
+
+    }
+}

+ 16 - 0
src/Yuuna.Contracts/Patterns/Builders/Cascadable.cs

@@ -0,0 +1,16 @@
+namespace Yuuna.Contracts.Patterns.Cascade
+{
+    using System.ComponentModel;
+    /// <summary>
+    /// 提供物件基本的級聯能力。這是 <see langword="abstract"/> 類別。
+    /// </summary>
+    [EditorBrowsable(EditorBrowsableState.Never)]
+    public abstract class Cascadable 
+    {  
+        protected Cascadable()
+        {
+        }
+
+        internal IInternalSession Session;
+    }
+}

+ 38 - 0
src/Yuuna.Contracts/Patterns/Builders/CascadeBuilder.cs

@@ -0,0 +1,38 @@
+
+
+namespace Yuuna.Contracts.Patterns.Cascade
+{
+    using System;
+    using System.Collections.Generic; 
+
+    /// <summary>
+    /// 級聯生成器,用以建立完整的級聯生成器模式。此類別可用於替代 <see cref="Initial{TNext}"/> 類別。
+    /// </summary>
+    /// <typeparam name="TNext">下個級聯類型。</typeparam>
+    public sealed class CascadeBuilder<TNext> : Initial<TNext>
+        where TNext : Cascadable, new()
+    {
+        private readonly Action<IReadOnlyList<object>> _onCompleted;
+
+        private CascadeBuilder(Action<IReadOnlyList<object>> onCompleted)
+        {
+            this._onCompleted = onCompleted;
+        }
+
+        /// <summary>
+        /// 建立新的 <typeparamref name="TNext"/> 級聯器實體。
+        /// </summary>
+        /// <param name="onCompleted"></param>
+        /// <returns></returns>
+        public static TNext Build(Action<IReadOnlyList<object>> onCompleted)
+        {
+            if (onCompleted is null)
+                throw new ArgumentNullException(nameof(onCompleted));
+            var init = new CascadeBuilder<TNext>(onCompleted);
+            return init.Next();
+        }
+
+        protected override void OnCompleted(IReadOnlyList<object> session) => this._onCompleted(session);
+
+    }
+}

+ 27 - 0
src/Yuuna.Contracts/Patterns/Builders/Initial.cs

@@ -0,0 +1,27 @@
+namespace Yuuna.Contracts.Patterns.Cascade
+{
+    using System.Collections.Generic;
+
+    /// <summary>
+    /// 初始級聯器。
+    /// 將繼承自這個級聯器的類別標示為整個級聯模式中的第一個級聯類型,用以連結下一個級聯物件。這是 <see langword="abstract"/> 類別。
+    /// </summary> 
+    /// <typeparam name="TNext">下個級聯類型。</typeparam>
+    public abstract class Initial<TNext> : Cascadable
+        where TNext : Cascadable, new()
+    {
+        protected Initial()
+        {
+            this.Session = new Session();
+            this.Session.Completed += this.OnCompleted;
+        }
+
+        protected abstract void OnCompleted(IReadOnlyList<object> session);
+
+        /// <summary>
+        /// 建立新的 <typeparamref name="TNext"/> 級聯器實體。
+        /// </summary>
+        /// <returns></returns>
+        public TNext Next() => new TNext { Session = this.Session };
+    }
+}

+ 12 - 0
src/Yuuna.Contracts/Patterns/Builders/Internal/IInternalEventBus.cs

@@ -0,0 +1,12 @@
+
+namespace Yuuna.Contracts.Patterns.Cascade
+{
+    using System;
+    using System.Collections.Generic;
+
+    internal interface IInternalEventDataBus
+    {
+        event Action<IReadOnlyList<object>> Completed;
+        void OnComplete();
+    }
+}

+ 10 - 0
src/Yuuna.Contracts/Patterns/Builders/Internal/IInternalSession.cs

@@ -0,0 +1,10 @@
+
+namespace Yuuna.Contracts.Patterns.Cascade
+{
+    using System.Collections.Generic;
+    using System.Collections.Immutable;
+
+    internal interface IInternalSession : IInternalStorage, IInternalEventDataBus, IReadOnlyList<object>
+    { 
+    }
+}

+ 8 - 0
src/Yuuna.Contracts/Patterns/Builders/Internal/IInternalStorage.cs

@@ -0,0 +1,8 @@
+
+namespace Yuuna.Contracts.Patterns.Cascade
+{  
+    internal interface IInternalStorage
+    {
+        void Store<T>(T data);
+    }
+}

+ 66 - 0
src/Yuuna.Contracts/Patterns/Builders/Internal/Session.cs

@@ -0,0 +1,66 @@
+
+namespace Yuuna.Contracts.Patterns.Cascade
+{
+    using System;
+    using System.Collections;
+    using System.Collections.Generic;
+    using System.Collections.Immutable;
+
+    internal sealed class Session : IInternalSession
+    {
+        private readonly List<object> _q;
+        private readonly object _lockObject;
+        internal Session()
+        {
+            this._lockObject = new object();
+            this._q = new List<object>();
+        }
+
+        #region IInternalEventDataBus 
+
+        private event Action<IReadOnlyList<object>> _completed;
+
+        event Action<IReadOnlyList<object>> IInternalEventDataBus.Completed
+        {
+            add => this._completed += value;
+            remove => this._completed -= value;
+        }
+
+        void IInternalEventDataBus.OnComplete() => this._completed?.Invoke(this);
+        #endregion
+
+        #region IInternalStorage 
+        void IInternalStorage.Store<T>(T data)
+        {
+            lock (this._lockObject)
+                this._q.Add(data);
+        }
+        #endregion
+
+        #region IReadOnlyList<object>
+
+        public object this[int index]
+        {
+            get
+            {
+                lock (this._lockObject)
+                    return this._q[index];
+            }
+        }
+
+        public int Count
+        {
+            get
+            {
+                lock (this._lockObject)
+                    return this._q.Count;
+            }
+        }
+
+        public IEnumerator<object> GetEnumerator() => this._q.ToImmutableList().GetEnumerator();
+        IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
+
+        #endregion
+
+    }
+}

+ 29 - 0
src/Yuuna.Contracts/Patterns/Builders/Output.cs

@@ -0,0 +1,29 @@
+
+
+namespace Yuuna.Contracts.Patterns.Cascade
+{
+    using System.Runtime.CompilerServices;
+
+    /// <summary>
+    /// 輸出級聯器。
+    /// 將繼承自這個級聯器的類別標示為最後一個級聯物件。這是 <see langword="abstract"/> 類別。
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    public abstract class Output<T> : Cascadable
+    { 
+        protected Output()
+        { 
+        }
+
+        /// <summary>
+        /// 將資料存入內部工作階段(Session)物件中,並通知所屬的級聯生成器已完成此次工作階段。
+        /// </summary>
+        /// <param name="data">資料。</param>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        protected void StoreData(T data)
+        {
+            this.Session.Store(data);
+            this.Session.OnComplete();
+        } 
+    }
+}

+ 31 - 0
src/Yuuna.Contracts/Patterns/Builders/Pipeline.cs

@@ -0,0 +1,31 @@
+
+namespace Yuuna.Contracts.Patterns.Cascade
+{
+    using System.Runtime.CompilerServices;
+
+    /// <summary>
+    /// 管道級聯器。
+    /// 將繼承自這個級聯器的類別標示為整個級聯模式中的中間級級聯物件,用以連結下一個級聯物件。這是 <see langword="abstract"/> 類別。
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    /// <typeparam name="TNext">下個級聯類型。</typeparam>
+    public abstract class Pipeline<T, TNext> : Cascadable
+        where TNext : Cascadable, new()
+    {
+
+        protected Pipeline()
+        {
+        }
+
+        /// <summary>
+        /// 將資料存入內部工作階段(Session)物件中後建立並返回新的 <see cref="TNext"/> 物件實體。
+        /// </summary>
+        /// <param name="data">資料。</param>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        protected TNext StoreData(T data)
+        {
+            this.Session.Store(data);
+            return new TNext { Session = this.Session };
+        }
+    }
+}

+ 13 - 0
src/Yuuna.Contracts/Patterns/Builders/readme.md

@@ -0,0 +1,13 @@
+# 級聯型生成器模式 (Cascade Builder Pattern)
+
+## 介紹及使用方式
+級聯型生成器模式,較傳統生成器模式多了流程引導,此種設計模式可以有效引導套件使用者使用函式。
+
+級聯元件具有三種
+- 初始級聯器 ```Initial<TNext>```
+- 管道級聯器 ```Pipeline<T,TNext>```
+- 輸出級聯器 ```Output<T>```
+
+連結模式
+Initial<TFirst> --> TFirst: Pipeline<T,TSecond> --> TSecond: Pipeline<T,...> -->
+... TLast: Output<T>

+ 0 - 1
src/Yuuna.Contracts/Patterns/Internal/BehaviourBuilder.cs

@@ -29,6 +29,5 @@ namespace Yuuna.Contracts.Patterns
             this._addMethod.Invoke(this._grammar, callback);
         }
     }
-
     public delegate Response Behaviour(IScore score);
 }

+ 6 - 5
src/Yuuna.Contracts/Patterns/Internal/PatternBuilder.cs

@@ -3,6 +3,7 @@ namespace Yuuna.Contracts.Patterns
 {
     using System;
     using System.Collections;
+    using System.Collections.Concurrent;
     using System.Collections.Generic;
     using System.Collections.Immutable;
     using System.Diagnostics;
@@ -12,8 +13,10 @@ namespace Yuuna.Contracts.Patterns
     using Yuuna.Contracts.Interaction;
     using Yuuna.Contracts.Optimization;
     using Yuuna.Contracts.Semantics;
-     
-    internal sealed class PatternBuilder : IPatternBuilder, IGrammarSet
+
+
+
+    internal sealed class PatternBuilder :  IGrammarSet, IPatternBuilder 
     {
         private readonly ImmutableDictionary<IGrammar, Behaviour>.Builder _rules;
         internal PatternBuilder() 
@@ -27,9 +30,7 @@ namespace Yuuna.Contracts.Patterns
         public bool TryGet(IGrammar grammar, out Behaviour behaviour)
         {
             return this._rules.TryGetValue(grammar, out behaviour);
-        }
-
-
+        } 
         IBehaviourBuilder IPatternBuilder.Build(IGroup group, params IGroup[] rest)
         {
             if (group is null)

+ 50 - 0
src/Yuuna.Contracts/Plugins/Fake.cs

@@ -0,0 +1,50 @@
+
+namespace Yuuna.Contracts.Plugins
+{
+    using Yuuna.Contracts.Interaction;
+    using Yuuna.Contracts.Patterns;
+    using Yuuna.Contracts.Semantics;
+    using Yuuna.Contracts.Utilities;
+
+    public sealed class Fake : PluginBase
+    {
+        protected override void BuildPatterns(IGroupManager g, IPatternBuilder p)
+        { 
+            g.Define("open").AppendOrCreate(new[] { "打開", "開" });
+            g.Define("door").AppendOrCreate(new[] { "門", "房間門" });
+            g.Define("light").AppendOrCreate(new[] { "燈", "檯燈" });
+            //g.Define("browser").AppendOrCreate(new[] { "瀏覽器", "chrome" });
+
+            p.Build(g["open"], g["door"]).OnInvoke(score =>
+            {
+                var DOOR = new { IS_OPENED = new[] { true, false, true, false }.RandomTakeOne() };
+                // 開門
+                if (!DOOR.IS_OPENED)
+                    return (Moods.Happy, "已經開好門囉 <3");
+                else
+                    return (Moods.Sad, "可是門本來就是開的欸 QAQ");  
+            });
+
+            p.Build(g["open"], g["light"]).OnInvoke(score =>
+            {
+                var LIGHT = new { IS_OPENED = new[] { true, false,true,false }.RandomTakeOne() };
+                // 開門
+                if (!LIGHT.IS_OPENED)
+                    return (Moods.Happy, "已經開好燈囉 <3");
+                else
+                    return (Moods.Sad, "可是燈本來就是開的欸 QAQ");
+            });
+
+            //p.Build(g["open"], g["browser"]).OnInvoke(score =>
+            //{
+            //    var DOOR = new { IS_OPENED = true };
+            //    // 開門
+            //    if (!DOOR.IS_OPENED)
+            //        return (Moods.Happy, "已經開好門囉 <3");
+            //    else
+            //        return (Moods.Sad, "可是門本來就是開的欸 QAQ");
+            //});
+        }
+    }
+
+}

+ 80 - 120
src/Yuuna.Contracts/Plugins/PluginBase.cs

@@ -4,165 +4,124 @@ namespace Yuuna.Contracts.Plugins
     using System;
     using System.Collections.Generic;
     using System.Collections.Immutable;
-    using System.Linq;
     using System.Runtime.CompilerServices;
-    using System.Text;
     using Yuuna.Contracts.Interaction;
     using Yuuna.Contracts.Optimization;
     using Yuuna.Contracts.Patterns;
+    using Yuuna.Contracts.Patterns.Cascade;
     using Yuuna.Contracts.Semantics;
     using Yuuna.Contracts.TextSegmention;
-    using Yuuna.Contracts.Utilities;
 
-    public sealed class Fake : PluginBase
+    public delegate Response Invoke(IScore score);
+    public delegate Response Incomplete(IScore score);
+
+    public interface IInvokeCreator
     {
-        protected override void BuildPatterns(IGroupManager g, IPatternBuilder p)
-        { 
-            g.Define("open").AppendOrCreate(new[] { "打開", "開" });
-            g.Define("door").AppendOrCreate(new[] { "門", "房間門" });
-            g.Define("light").AppendOrCreate(new[] { "燈", "檯燈" });
-            //g.Define("browser").AppendOrCreate(new[] { "瀏覽器", "chrome" });
+        IIncompleteCreator OnInvoke(Invoke invoke);
+    }
 
-            p.Build(g["open"], g["door"]).OnInvoke(score =>
-            {
-                var DOOR = new { IS_OPENED = new[] { true, false, true, false }.RandomTakeOne() };
-                // 開門
-                if (!DOOR.IS_OPENED)
-                    return (Moods.Happy, "已經開好門囉 <3");
-                else
-                    return (Moods.Sad, "可是門本來就是開的欸 QAQ");  
-            });
-
-            p.Build(g["open"], g["light"]).OnInvoke(score =>
-            {
-                var LIGHT = new { IS_OPENED = new[] { true, false,true,false }.RandomTakeOne() };
-                // 開門
-                if (!LIGHT.IS_OPENED)
-                    return (Moods.Happy, "已經開好燈囉 <3");
-                else
-                    return (Moods.Sad, "可是燈本來就是開的欸 QAQ");
-            });
-
-            //p.Build(g["open"], g["browser"]).OnInvoke(score =>
-            //{
-            //    var DOOR = new { IS_OPENED = true };
-            //    // 開門
-            //    if (!DOOR.IS_OPENED)
-            //        return (Moods.Happy, "已經開好門囉 <3");
-            //    else
-            //        return (Moods.Sad, "可是門本來就是開的欸 QAQ");
-            //});
+    public interface IIncompleteCreator
+    {
+        void OnIncomplete(Incomplete incomplete);
+    }
+     
+    public sealed class IncompleteCreator : Output<Incomplete>, IIncompleteCreator
+    {
+        public void OnIncomplete(Incomplete incomplete)
+        {
+            //if (incomplete is null)
+            //    throw new ArgumentNullException(nameof(incomplete));
+            this.StoreData( incomplete);
         }
     }
 
-
-    public class PluginHub
+    public sealed class InvokeCreator : Pipeline<Invoke, IncompleteCreator>, IInvokeCreator
     {
-        public PluginHub()
+        public IIncompleteCreator OnInvoke(Invoke invoke)
         {
+            //if (invoke is null)
+            //    throw new ArgumentNullException(nameof(invoke));
 
+            return this.StoreData(invoke);
         }
+    }
 
+    public interface IGrammarCreator
+    {
+        IInvokeCreator Build(IGroup group, params IGroup[] rest);
+    }
 
-
-        public static void Main(string[] args)
-        {
-            // Send("打開門");
-            // Send("開燈");
-            // Send("打開燈"); 
-        }
-
-        public static void Send(string text)
+    public sealed class GrammarCreator : Pipeline<IGrammar, InvokeCreator>, IGrammarCreator
+    {
+        public IInvokeCreator Build(IGroup group, params IGroup[] rest)
         {
-            ITextSegmenter segmenter = new JiebaTextSegmenter();
-            var allPlugins = new PluginBase[] { new Fake() };
-            foreach (var item in allPlugins)
-            {
-                item.Initialize(segmenter);
-                Console.WriteLine("已載入模組: "+item.GetType().AssemblyQualifiedName);
-            }
-
-            Console.WriteLine("我: " + text);
-            var cutted = segmenter.Cut(text);
-            Console.WriteLine($"來自分詞器 {segmenter.Name} 的分詞結果: [ {string.Join(", ",cutted)} ]");
-            var strategy = new DefaultStrategy();
-            var list = new List<IScore>();
-            foreach (var p in allPlugins) 
-                list.AddRange(p.Evaluate(strategy, cutted));
-            list.Sort(ScoreComparer.Default);
-
-            var sb = new StringBuilder("Bot: ");
-            var best = list.LastOrDefault();
-            if (best is null)
-                sb.Append("我不懂你的意思");
-            else if (best.IsCompacted)
-            {
-                var resp = best.Plugin.SelectBest(best).Invoke(best);
-                Console.WriteLine(   resp.Mood.ToString());
-                sb.Append(resp.Message);
-            }
-            else
-            {
-                var choices = list.Where(s => s.Missing.Count <= 1).ToImmutableArray();
-                switch (choices.Length)
-                {
-                    case 1:
-                        {
-                            sb.Append("你" + new[] { "是想", "想要" }.RandomTakeOne() + " ");
-                            sb.Append(choices.Select(x => x.Contrast.ToImmutable().Aggregate(string.Empty, (s, g) => s += g.ToImmutable().RandomTakeOne().ToImmutable().RandomTakeOne())));
-                            sb.Append(" 嗎?");
-                        }
-                        break;
-
-
-                    case 2:
-                        {
-                            sb.Append("你" + new[] { "是想", "想要" }.RandomTakeOne() + " ");
-                            sb.AppendJoin(" 還是 ", choices.Select(x => x.Contrast.ToImmutable().Aggregate(string.Empty, (s, g) => s += g.ToImmutable().RandomTakeOne().ToImmutable().RandomTakeOne())));
-                            sb.Append(" ?");
-                        }
-                        break;
-
-
-                    default:
-                        sb.Append("我不太清楚你想做什麼");
-                        break;
-                }
-            }
-
-            Console.WriteLine(sb);
-
+            //if (group is null)
+            //    throw new ArgumentNullException(nameof(group));
+            var g = new Grammar();
+            //g.Add(group);
+            //if (rest != null)
+            //    foreach (var item in rest)
+            //    {
+            //        g.Add(item);
+            //    }
+            //g.Immute();
+
+            return this.StoreData( g);
         }
     }
+     
+
 
     public abstract class PluginBase
     {
-        private readonly PatternBuilder _grammarSet;
-        private readonly GroupManager _groupManager;
+        private readonly PatternBuilder _grammarSet; 
          
 
         public PluginBase()
         {
             this._grammarSet = new PatternBuilder();
-            this._groupManager = new GroupManager();
         }
 
-        protected virtual void PreInitialize(ITextSegmenter segmenter)
+        /// <summary>
+        /// 在初始化前引發。
+        /// </summary>
+        /// <param name="segmenter"></param>
+        protected virtual void BeforeInitialize(ITextSegmenter segmenter)
         { 
         }
 
-        internal void Initialize(ITextSegmenter textSegmenter)
+        internal bool Initialize(ITextSegmenter textSegmenter)
         {
-            this.PreInitialize(textSegmenter);
-            this.BuildPatterns(this._groupManager, this._grammarSet);
-            textSegmenter.Load(this._groupManager);
-            this.OnInitialize();
+            try
+            {
+                
+
+                this.BeforeInitialize(textSegmenter);
+                var groupManager = new GroupManager();
+                this.BuildPatterns(groupManager, this._grammarSet);
+                textSegmenter.Load(groupManager);
+                this.AfterInitialize();
+                return true;
+            }
+            catch
+            {
+                return false;
+            }
         }
-        protected virtual void OnInitialize()
+
+        /// <summary>
+        /// 在初始化後引發。
+        /// </summary>
+        protected virtual void AfterInitialize()
         {
         }
 
-        protected abstract void BuildPatterns(IGroupManager groupManager, IPatternBuilder grammarBuilder);
+        /// <summary>
+        /// 建立模式規則。
+        /// </summary>
+        /// <param name="g"></param>
+        /// <param name="p"></param>
+        protected abstract void BuildPatterns(IGroupManager g, IPatternBuilder p);
 
         internal IImmutableList<IScore> Evaluate(StrategyBase strategy, IImmutableList<string> cutted)
         {
@@ -175,4 +134,5 @@ namespace Yuuna.Contracts.Plugins
         }
     }
 
+
 }

+ 129 - 0
src/Yuuna.Contracts/Plugins/PluginGateway.cs

@@ -0,0 +1,129 @@
+
+namespace Yuuna.Contracts.Plugins
+{
+    using System;
+    using System.Collections.Generic;
+    using System.Collections.Immutable;
+    using System.Linq;
+    using System.Text;
+    using Yuuna.Contracts.Optimization;
+    using Yuuna.Contracts.Patterns.Cascade;
+    using Yuuna.Contracts.Patterns;
+    using Yuuna.Contracts.TextSegmention;
+    using Yuuna.Contracts.Utilities;
+
+    public class PluginGateway
+    {
+        public PluginGateway()
+        {
+
+        }
+
+        class A : Pipeline<string,B>
+        {
+            public B a(string v)
+            {
+                return this.StoreData(v);
+            }
+        }
+        class B : Pipeline<string,C>
+        {
+            public C b(string v)
+            {
+                return this.StoreData(v);
+            }
+        }
+        class C : Pipeline<string, D>
+        {
+            public D c(string v)
+            {
+                return this.StoreData(v);
+            }
+        } 
+        class D: Output<string>
+        {
+            public void d(string v)
+            {
+                this.StoreData(v);
+            }
+        }
+
+        public static void Main(string[] args)
+        {
+            var builder = CascadeBuilder<A>.Build(session => 
+            {
+                foreach (var item in session)
+                {
+                    Console.WriteLine(item);
+                }
+            });
+            builder.a("---a").b("---b").c("---c").d("---d");
+            // Send("打開門");
+            // Send("開燈");
+            // Send("打開燈"); 
+        }
+
+        public static void Send(string text)
+        {
+            ITextSegmenter segmenter = new JiebaTextSegmenter();
+            var allPlugins = new PluginBase[] { new Fake() };
+            foreach (var item in allPlugins)
+            {
+                item.Initialize(segmenter);
+                Console.WriteLine("已載入模組: "+item.GetType().AssemblyQualifiedName);
+            }
+
+            Console.WriteLine("我: " + text);
+            var cutted = segmenter.Cut(text);
+            //Console.WriteLine($"來自分詞器 {segmenter.Name} 的分詞結果: [ {string.Join(", ",cutted)} ]");
+            var strategy = new DefaultStrategy();
+            var list = new List<IScore>();
+            foreach (var p in allPlugins) 
+                list.AddRange(p.Evaluate(strategy, cutted));
+            list.Sort(ScoreComparer.Default);
+
+            var sb = new StringBuilder("Bot: ");
+            var best = list.LastOrDefault();
+            if (best is null)
+                sb.Append("我不懂你的意思");
+            else if (best.IsCompacted)
+            {
+                var resp = best.Plugin.SelectBest(best).Invoke(best);
+                Console.WriteLine(   resp.Mood.ToString());
+                sb.Append(resp.Message);
+            }
+            else
+            {
+                var choices = list.Where(s => s.Missing.Count <= 1).ToImmutableArray();
+                switch (choices.Length)
+                {
+                    case 1:
+                        {
+                            sb.Append("你" + new[] { "是想", "想要" }.RandomTakeOne() + " ");
+                            sb.Append(choices.Select(x => x.Contrast.ToImmutable().Aggregate(string.Empty, (s, g) => s += g.ToImmutable().RandomTakeOne().ToImmutable().RandomTakeOne())));
+                            sb.Append(" 嗎?");
+                        }
+                        break;
+
+
+                    case 2:
+                        {
+                            sb.Append("你" + new[] { "是想", "想要" }.RandomTakeOne() + " ");
+                            sb.AppendJoin(" 還是 ", choices.Select(x => x.Contrast.ToImmutable().Aggregate(string.Empty, (s, g) => s += g.ToImmutable().RandomTakeOne().ToImmutable().RandomTakeOne())));
+                            sb.Append(" ?");
+                        }
+                        break;
+
+
+                    default:
+                        sb.Append("我不太清楚你想做什麼");
+                        break;
+                }
+            }
+
+            Console.WriteLine(sb);
+
+        }
+    }
+
+}