Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/matlab/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F# F中的中介作用#_F# - Fatal编程技术网

F# F中的中介作用#

F# F中的中介作用#,f#,F#,我有一个问题,我想基于f#中的singelton创建某种中介。主要原因是我需要在应用程序的一个部分注册一些操作,然后在另一个类似于c#的部分执行它,如下所示: public class Mediator { private static readonly object syncRoot = new object(); private static Mediator instance; public static Mediator Instance {

我有一个问题,我想基于f#中的singelton创建某种中介。主要原因是我需要在应用程序的一个部分注册一些操作,然后在另一个类似于c#的部分执行它,如下所示:

public class Mediator
{
    private static readonly object syncRoot = new object();
    private static Mediator instance;

    public static Mediator Instance
    {
        get
        {
            if (instance == null)
            {
                lock (syncRoot)
                {
                    if (instance == null)
                    {
                        instance = new Mediator();
                    }
                }
            }

            return instance;
        }
    }

    public event Action<string> InputLogUpdate;
    public void InvokeInputLogUpdate(string msg)
    {
        InputLogUpdate?.Invoke(msg);
    }
}
Mediator.Instance.InvokeInputLogUpdate(msg);
Mediator.Instance.InputLogUpdate += msg => this.DebugSection += $"{msg} \n";
注册表看起来像:

public class Mediator
{
    private static readonly object syncRoot = new object();
    private static Mediator instance;

    public static Mediator Instance
    {
        get
        {
            if (instance == null)
            {
                lock (syncRoot)
                {
                    if (instance == null)
                    {
                        instance = new Mediator();
                    }
                }
            }

            return instance;
        }
    }

    public event Action<string> InputLogUpdate;
    public void InvokeInputLogUpdate(string msg)
    {
        InputLogUpdate?.Invoke(msg);
    }
}
Mediator.Instance.InvokeInputLogUpdate(msg);
Mediator.Instance.InputLogUpdate += msg => this.DebugSection += $"{msg} \n";
但现在运气不好,我所得到的只是:

vnamespace Operation.Mediator

module Mediator = 
open System
type UdpMediator private () =

    static let instance = UdpMediator()
    let mutable UpdateDebigLog : Action<string> = null

    static member Instance = instance
    member this.InvokeUpdateLog (msg:string) = UpdateDebigLog.Invoke(msg)
vnamespace操作.Mediator
模块中介=
开放系统
类型UdpMediator private()=
静态let实例=UdpMediator()
让可变UpdateBigLog:Action=null
静态成员实例=实例
成员this.InvokeUpdateLog(msg:string)=updatedBiglog.Invoke(msg)
而且它的效果也不是很好,任何人都知道如何做到这一点。

尝试在F#中使用C#、OOP风格的设计模式通常会导致与用惯用F#表达事物的自然方式相比,事情过于复杂。您所说的您需要的是一种方法,让代码的一部分注册一个操作,如果已注册,则让代码的另一部分执行已注册的操作。因为您使用的是事件,所以我假设您希望能够注册多个操作并触发所有操作。这里有一些代码可以做到这一点:

module ActionRegistry

let mutable private actions : (string -> unit) list = []

let register f =
    actions <- f :: actions

let invokeRegisteredActions() =
    actions
    |> List.iter (fun action -> action())
模块操作注册表
让可变私有操作:(字符串->单位)列表=[]
让我们注册f=
actions List.iter(趣味动作->动作())
现在,这不是比单例中介类更容易理解吗?OOP风格的设计模式总是使事情过于复杂


另外,你没有提到注销操作,所以我让设计简单,没有包含注销功能。如果您确实需要注销操作,我会做一些事情,比如保留一个(int,action)对的列表,使用一个简单的递增计数器确保对的int部分不断增加。然后,register函数将返回一个int,unregister函数将获取一个int并过滤掉第一个位置的int对。

首先,夹在两个
null
检查之间的
锁的模式太过时了,我甚至不记得上次看到它是什么时候了。现代的.NET为这种按需初始化提供了
Lazy
。幸运的是,F#实际上有特殊的语法:

type UpdMediator private () =

    static member val private _instance = lazy UpdMediator()
    static member Instance = UpdMediator._instance.Value
,C#中的
事件动作
不等同于F#中的
可变动作
。C中的
事件
声明实际上创建了两个访问器方法-
添加
删除
,就像
获取
设置
属性一样

然而,F#实际上有一个更好的机制-
事件
。将该类型的实例设为私有,然后通过其
.Publish
属性将其公开,该属性的类型为
IEvent
。使用者可以使用该
IEvent
值添加和删除处理程序,或订阅事件可观察样式(因为
IEvent
继承自
IObservable
):

类型UpdMediator private()=
...
成员val private _updDebugLog=Event()
成员this.UpdDebugLog=this.\u UpdDebugLog.Publish
成员this.InvokeUpdDebugLog()=this.\u updDebugLog.Trigger“foo”
//用法:
UpdMediator.Instance.UpdDebugLog.AddHandler(趣味发件人str->printfn“%s”str)
//或可观察的风格:
UpdMediator.Instance.UpdDebugLog.Subscribe(printfn“%s”)
(请注意,
.Subscribe
返回一个
IDisposable
,稍后可用于取消订阅)

第三,试图将C#实践逐字翻译成F#实践通常不会有好结果。F#通常比C#有更好的功能,因此逐字翻译通常会有点尴尬,正如您的案例所示


最后,请注意,“工作不太好”不是问题的好描述。如果您希望从社区获得指导或建议,请花时间描述问题的具体情况、您预期会发生什么、您如何尝试实现它,等等。有关一些提示,请参阅。

请注意,这将按与注册顺序相反的顺序触发事件,例如后进先出顺序。如果需要FIFO顺序,则将
f::actions
更改为
List.append actions[f]
。这是一个O(N)运算,而不是O(1),所以你的整体运算是O(N^2)。但是我怀疑你会记录更多的动作,所以对于低N,O(N)和O(N^2)之间的差异真的不重要;警察用了锁。如果需要线程安全,System.Collections.Concurrent.ConcurrentQueue或System.Collections.Concurrent.ConcurrentStack将比普通列表更好。或者在模块内使用单个
MailboxProcessor
来管理状态并按顺序调用操作。