【问题标题】:How to make class that can only be accessed through interface?如何制作只能通过接口访问的类?
【发布时间】:2014-09-13 16:03:27
【问题描述】:

在 C# 或 Java 中,我怎样才能创建一个只能用它实现的接口实例化的类?

对不起,如果之前有人问过这个问题。

编辑:很抱歉让您感到困惑,这个问题只是出于好奇:

例如我有:

interface iA
{
  int addNum();
}

interface iB
{
  int minusNum();
}

class A implements iA, iB
{
  private int A;
  public int addNum()
  {
    A += 10;
    return A;
  }

  public int minusNum()
  {
    A -= 10;
    return A;
  }
}

class TestIface
{
  public static void main(String args[]) {
    A testA = new A();
    iA testiA = new A();
    iB testiB = new A();

    testA.minusNum(); // No error, it has access to both methods
    testA.addNum();

    testiA.minusNum();//ERROR
    testiA.addNum();

    testiB.minusNum();
    testiB.addNum();//ERROR
  }
}

我想知道是否有办法阻止开发人员只创建 testA 并访问这两种方法。

【问题讨论】:

  • 不存在这样的东西。
  • 这样做有什么收获?
  • 你可以潜在地使实现成为一个只返回接口的工厂的嵌套类。问题是,为什么?
  • 1.创建一个工厂并仅使用该工厂(提供者模式)实例化您的类,2.使用实例化类的 Unity Container。第三条建议是解释原因,然后您可以获得更好的答案

标签: java c# oop interface


【解决方案1】:

将构造函数设为私有怎么样?

class A implements iA
{
  public int returnNum()
  {
    return 10;
  }
  private A(){}

  public static iA getInstance(){
    return new A();
  }

}

【讨论】:

  • 发布的代码是无用的(除非您将 getInstance 设为静态)
  • 这不会阻止某人创建另一个使用公共构造函数的接口的具体实现,因此不会满足 OP 的(不可能的)要求。
  • @HovercraftFullOfEels 你能解释一下“创建另一个使用公共构造函数的接口的具体实现”吗,我不明白?
  • @Tr1et 他指出没有办法阻止某人在具有公共构造函数的新类中实现iA
【解决方案2】:

您可以将构造函数设为私有并定义创建新实例的静态 Create 方法。

  public interface ITest
  {
  }
  public class A : ITest
  {
      private A()
      {
      }
      public static ITest Create()
      {
          return new A();
      }
  }

那么创建类实例的唯一方法(除了反射,但这是另一回事!)是这样调用 Create 方法:

ITest test = A.Create();

【讨论】:

  • 那么,为什么不:A test = A.Create(),test 仍然可以访问大多数方法,对吧?
  • 你不能这样做,因为它会给你一个编译错误。将 A.Create() 结果用作 A 实例的唯一方法是通过显式强制转换。
  • @Tr1et 因为调用者只知道A.Create 返回一个ITest 的实例。 A.Create 的实现实际上返回了A 的一个实例,这是一个带有方法签名的实现细节。
【解决方案3】:

你不能通过接口实例化一些东西。您只能将其声明为接口。如果您的目标是使addNum 只能通过iA 访问,而minusNum 只能通过iB 访问,您可以尝试显式接口实现(尽管它有其自身的缺点):

class A : iA, iB
{
    private int A;

    int iA.addNum()
    {
        A += 10;
        return A;
    }

    int iB.minusNum()
    {
        A -= 10;
        return A;
    }
}

这至少会给你你正在寻找的编译时效果:

class TestIface
{
    public static void main(String args[]) {

        A testA = new A();
        testA.minusNum(); // does not compile
        testA.addNum();   // does not compile

        iA testiA = new A ();
        testiA.minusNum();//does not compile
        testiA.addNum();

        iB testiB = new A ();
        testiB.minusNum();
        testiB.addNum();//does not compile
    }
}

但是,这并不意味着addNum 只能通过声明iA 的变量访问。为了说明,你可以这样做:

A testObj = new A ();
(testObj as iA).addNum (); // this will compile

你甚至可以这样做:

iB testObj = new A ();
(testObj as iA).addNum (); // this will also compile, and execute fine

如果您想进一步防止从具体类到具体类的显式强制转换,您需要采纳其他人提供的建议:将您的具体类设置为嵌套的私有类并引入一个工厂来生成实例:

class Factory
{
    private class A : iA, iB
    {
        int iA.addNum () {...}
        int iB.minusNum () {...}
    }

    public iA GetInstanceOfiA () 
    {
        return new A ();
    }

    public iB GetInstanceOfiB () 
    {
        return new A ();
    }
}

这仍然不能阻止从 iA 到 iB 的转换,我猜你必须创建两个单独的具体类来满足。

【讨论】:

  • 谢谢,我很惊讶它能够写出类似 iA.addNum() 的方法,它是 Java 独有的还是 C# 也可用?
  • 它是特定于 C# 的。在 StackOverflow 或 Goggle 上搜索“显式接口实现”会给出很多示例
猜你喜欢
  • 2014-06-11
  • 1970-01-01
  • 2021-09-12
  • 2021-01-04
  • 1970-01-01
  • 1970-01-01
  • 2012-12-08
  • 2013-11-15
  • 1970-01-01
相关资源
最近更新 更多