委托的封装问题

本文关键字:问题 封装 | 更新日期: 2023-09-27 18:05:31

我想知道为什么这工作?

例如,我有一些执行器类看起来像这样:

public class Executor
{
    public void Execute(Action action)
    {
        action();
    }
}

现在我有一些需要执行类看起来像:

public class NeedToBeExecuted
{
    public void Invoke()
    {
        Executor executor = new Executor();
        executor.Execute(DoSomething);
    }
    private void DoSomething()
    {
        // do stuff private
    }
}

我的问题是为什么这是工作的我传递一个私有方法其他类?

这不是封装问题吗?

委托的封装问题

不,这并没有违反封装。

首先:类本身决定将委托分发给它的一个私有方法!类可以访问它的私有方法,如果它选择将对一个方法的引用传递给该方法的可访问域之外的代码,那完全是在它的权利范围内。

第二:方法的可访问域不限制方法可以在的位置被调用。它限制了方法可以通过名称查找的位置。类Executor从不使用名称 DoSomething来调用私有方法。使用名称action

让我试一试。

不,我们没有封装问题。您正在定义一个对Execute负责的类。Executer不知道实际执行的内容。它只知道应该执行DoSomethingDoSomething所做的是在负责执行某事的类中指定的。

正如我所评论的,这与您使用Thread所做的非常相似。您定义了一个需要在另一个线程上执行的方法。这就是为什么类有一个线程,并定义了应该在该线程上运行的方法。线程仍然对它所在的类一无所知。

关系是Class => Thread。而不是反过来。

在您的示例中,关系是NeedToBeExecuted => Executer。而不是反过来。

这个概念对你来说可能很棘手,但你并没有做错什么。

这只是和使用反射一样的封装问题。使用反射可以很容易地从外部类访问私有方法和变量。你不应该认为这是一件坏事,因为它只是使语言更加强大。

类是一个放弃委托方法,所以在某种程度上类是启用的行为,所以它不应该是一个封装问题。

考虑一下:NeedToBeExecuted并没有以这样一种可以任意调用的方式公开DoSomething()方法,而是将其作为委托传递给另一个函数。它可以很容易地通过() => DoSomething() -结果是一样的。最终,访问修饰符的存在是为了防止不同的类使用您的方法,您仍然可以随意使用它。如果您选择将它传递给另一个类,这是一个有效的用法。

封装意味着能够在不改变外部代码的情况下改变某些模块的内部。这里仍然是这样。

在方法Invoke()中传递DoSomething,并且可以在上下文中访问它。没有封装问题。

但是,正如您在代码中看到的注释,DoSomething无法在EitherNeedToBeExecuted中访问。

public class Executor {
    public void Execute(Action action) {
        action();
    }
}
public class NeedToBeExecuted {
    public virtual void Invoke() {
        Executor executor=new Executor();
        executor.Execute(this.DoSomething);
    }
    private void DoSomething() {
        Console.WriteLine("I'M DOING IT MYSELF!!");
    }
    protected Executor m_Executor=new Executor();
}
public class EitherNeedToBeExecuted: NeedToBeExecuted {
    public override void Invoke() {
        // 'NeedToBeExecuted.DoSomething()' is inaccessible due to its protection level
        m_Executor.Execute(base.DoSomething);
    }
}