繁体   English   中英

Java:有没有办法强制执行私有方法?

[英]Java: Is there a way to you enforce a implementation of private methods?

我有5或6个类,我想在内部遵循相同的基本结构。 真正大多数类应该遵循的只是函数本身的使用,所以我真的希望这些方法是私有的。

有没有办法实现这个目标? 我知道接口可以很好地工作,但它们不会占用私有成员,也不会允许您重新定义已实现方法中的作用域。 这有什么解决方法吗?

谢谢

我认为最接近的是使用带abstract protected方法的abstract类:

abstract class A {
    protected abstract void foo();
}

class B extends A {
    protected void foo() {}
}

要定义公共逻辑,可以从超类中的私有方法调用protected方法:

abstract class A {
    private void bar() {
        // do common stuff
        foo();
    }
    protected abstract void foo();
}

这样,您可以允许子类使用特定行为填充私有公用模板方法

创建一个概述结构和公共流程的抽象基类。 为继承类必须实现的流中的步骤指定抽象方法。

嗯,私有函数不能被任何其他类调用, 即使是子类也是如此 那么在不同的类中使用相同名称的私有函数有什么意义呢?

在编译时无法强制执行它,但是您可以编写单元测试或简单程序来使用反射来测试方法的存在。

我假设你这样做是为了使课程符合美学/设计原因。 如果你出于其他原因这样做,你应该真正使用其他人建议的抽象保护方式。

这里有一些代码可以让你开始进行这样的工具/单元测试(你至少应该改进错误消息,我真的建议单元测试,而不是我在这里有什么):

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class Main
{
    public static void main(String[] args) 
    {
        check(B.class, Modifier.PRIVATE, void.class, "doit", new Class<?>[] { int.class });
        check(C.class, Modifier.PRIVATE, void.class, "doit", new Class<?>[] { int.class });
    }

    private static void check(final Class<?>   clazz,
                              final int        modifiers,
                              final Class<?>   returnType,
                              final String     name,
                              final Class<?>[] params)
    {
        try
        {
            final Method method;

            method = clazz.getDeclaredMethod(name, params);

            if(method.getModifiers() != modifiers)
            {
                System.out.println("modifiers do not match");
            }

            if(method.getReturnType() != returnType)
            {
                System.out.println("return type does not match");
            }
        }
        catch(final NoSuchMethodException ex)
        {
            System.out.println("could not find method");
        }
    }
}

interface A
{
    void foo();
}


class B
    implements A
{
    public void foo()
    {
        doit(0);
    }

    private void doit(final int x)
    {
    }
}

class C
    implements A
{
    public void foo()
    {
        doit(0);
    }

    private int doit(final int x)
    {
        return (5);
    }
}

创建一个大纲'common'类,其中包含所有私有方法。

然后创建5或6个类,每个类都有一个类型为'common'的字段。 当然,你无法调用私有方法(但是你说这些方法实际上是内部的) - 当然,你还必须宣传一些公共方法来改变状态。

public class common { 
    private method1() { ; }
    private method2() { ; }
    public other() { ; }
...
}

public class myclass1 { 
    common commonMethods;
}

public class myclass2 { 
    common commonMethods;
}

或者甚至(假设'common'定义如上):

public class template {
    common commonMethods;
}

public class myclass1 extends template {
...
}

因此,您可以在5或6个子类的每一个上获得(包受保护的)“commonMethods”字段,用于“free”。

在对此线程进行后续讨论后,似乎作者实际上并不想共享逻辑:只是方法签名本质上,所以这个答案不符合该要求。

虽然接口方法本身必须始终是公共的,但您可以将接口包设为私有,并将所有Car(例如)实现保留在同一个包中。

package com.some.car.pkg;

interface Car
{
    public void gas();
    public void brake();
}

即使这些方法是公开的,也没关系,因为在com.some.car.pkg包之外,Car是不可见的。 这样,您的所有实现者都不会被迫扩展抽象类。 你需要常用方法的事实意味着真正的私有并不是真正的解决方案,恕我直言,你想要一个接口,因为在你的情况下,抽象类听起来不太合适,因为没有共享逻辑。

我的2美分。

使用标记为final的方法创建一个抽象基类,该方法描述包含私有方法的公共流。 将其标记为final意味着它不能通过子类进行扩展,因此只要您的调用代码使用它,就会强制执行业务逻辑。 可以通过将方法标记为受保护来创建扩展点。 例如,假设您有一个代表零售商店的类。

private final void doTransaction() {
    float amountDue;

    // a protected or abstract method that extenders can override
    Collection items = this.unloadShoppingCart();

    for (Object item : items) {
        // another protected or abstract method
        amountDue +=  this.getPrice(item);
    }

    // your private method 
    amountDue += this.getSalesTax(amountDue);

}

“throw MethodNotImplementedException();” 可能是一个有用的结构。

如果抽象保护确实没有足够的保护,我想知道关注的是什么。 在任何情况下,类似于monojohnny的替代方案是使用策略模式。 这可以确保:

  • 派生类必须定义行为
  • 派生类在定义后无法访问该行为
  • 实例无法访问彼此的行为

尽管如此,尽管没有汽车印章,但是借用汽车隐喻道歉:

public interface GearBoxStrategy {
    public void changeGear(int newGear);
}

abstract public class Car {
    private GearBoxStrategy gearBox;
    public Car(GearBoxStrategy g) {
       this.gearBox = g;
    }

    public void accelerate(double targetSpeed) {
        int gear = getTargetGear(targetSpeed):
        gearBox.shift(gear);
    }
}

public class AutomaticTransmissionCar {
    public AutomaticTransmissionCar() {
        super(new AutomaticTransmissionGearBoxStrategy());
    }
}

public class ManualTransmissionCar {
    public ManualTransmissionCar() {
        super(new ManualTransmissionGearBoxStrategy());
    }
}

看一下XDepend,它使用反射根据编译的代码创建数据库。

http://www.xdepend.com

它针对的是希望能够快速检查潜在大型编译代码库以寻找潜在问题区域的软件架构师。 它具有内置的报告和可视化功能,例如类之间的关系,圈复杂度,耦合等。

此外,它还包括一个内置的sql,如查询语言“CQL”(用于“代码查询语言”)。 使用CQL,您可以定义自己的报告。 您可能应该能够使用它来定义违反所描述规则的报告。 此外,您可以使用注释将CQL查询直接嵌入到代码中。

我没有调查它,但使用它的.NET等效'NDepend',它是一个非常酷的工具。

当然,您也可以编写自己的自定义工具,该工具使用反射来检查您的特定规则。 XDepend可能仍然值得一看 - 它应该更加灵活。

是否可以使所有类继承自同一个基类?

如果是这样,您可以考虑的一件事是在运行时在基类的构造函数中使用反射来验证子类是否遵循您描述的规则 ,并在验证规则失败时抛出异常。

当然,这个测试的天真实现会产生很大的性能问题,所以你必须对实现测试的方式非常聪明。

首先,测试应该只针对特定子类型T的所有实例运行一次。因此,您必须在某处缓存验证信息。 一种方法是在基类中使用某种静态(全局)哈希表,键入每个子类型的类型。

您还必须围绕此缓存执行某种线程安全同步。 你真正需要避免的是读取的性能损失。 我之前在类似情况下所做的是使用双重检查锁定模式和使用不可变哈希表的组合,这样在尝试写入哈希表时(即当您创建哈希表时)只会锁定性能特定子类型T)的第一个实例。

我实际上没有Java经验,我描述的,我在.NET中实现,这就是为什么我不能为你提供代码示例,但所有的概念都应该很容易转移到Java - 我提到的一切都是(AFAIK) )可在两个平台上使用。

考虑使用抽象基类。 这是一篇陈旧但相关的文章: http//www.javaworld.com/javaworld/javaqa/2001-04/03-qa-0420-abstract.html

这是一个想法:编写一个简单的文本解析器来检查方法的存在。 将其作为Ant中的任务包含在内。 只要您坚持某种形式的编码标准,一些简单的文本匹配就应该这样做,即只需在所需的源文件中查找格式化的签名即可。

在评论中,你写道“是的,这是重点。我知道它们可以被称为不同的东西,但我不希望它们成为。”

impossible, it's just a lot of work. 现在,有些人可能会说“那是不可能的”,但就像编程中的大多数事情一样, 不可能的,这只是很多工作。

如果您真的想要这样做,您可以为您的类创建一个自定义Java注释 ,然后编写一个Annotation处理器并在构建过程中调用apt。

就像我说了很多工作一样,但如果你想了解Annotations的工作方式,那可能是值得的。


编写注释实际上非常简单。 他们的工作方式类似于普通班级。 annotation like this 例如,如果您只是想出于某种原因标记一个类,可以像这样创建一个空或注释

public @interface Car { }

然后在您的注释处理器中,您可以检查以确保Car具有正确的私有方法。

我已经编写了自己的注释,但是我在运行时使用反射API检查了它们,而不是在构建时。 它们实际上非常简单。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM