tags:

views:

285

answers:

14

I have 5 or 6 classes that I want to have follow the same basic structure internally. Really most of those that the classes should follow are just for the use of the function itself, so I really want these methods to be private.

Is there any way to achieve this? I know interfaces would work great but they won't take private members and won't allow you to redefine the scope in the implemented method. Is there any workaround for this?

Thanks

+5  A: 

Create an abstract base class that outlines the structure and common flow. Specify abstract methods for the steps in the flow that must be implemented by the inheriting classes.

Paolo
I upvoted this without realizing that it didn't answer the question. Like I said I was looking to be able to enforce private methods. Abstract classes wont do that
John Baker
I see what you were after now. Abstract classes are the only way you can enforce a common internal structure and flow for inheriting classes, the trade-off is you can't use private methods to do it.There is no way to enforce the internals of a private method across classes I'm afraid.
Paolo
A: 

Look into using an abstract base class. Here's an old but relevant article: http://www.javaworld.com/javaworld/javaqa/2001-04/03-qa-0420-abstract.html

Jason Nichols
+13  A: 

I think the closest you can get is using an abstract class with abstract protected methods:

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

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

To define common logic, you can call the protected method from a private method in the super class:

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

This way, you can allow subclasses to fill the private common template method with specific behavior.

Fabian Steeg
Yeah that is interesting. Unfortunately I don't have any common logic I'd just like to force all the objects to use the same internal methods. That's a shame that you can't force private on them.
John Baker
An abstract class can also have abstract package-private methods, so if you can force the subclasses to be in the same package, then those methods can be almost as private.
Yishai
+4  A: 

Hmm, private functions can't be called by any other classes, even by subclasses. So what's the point in having private functions with the same name in different classes?

Chad Okere
If you had different types of car objects and wanted to have them all implement certain methods yet protect them from other objects having access how would you achieve this?
John Baker
But if they are protected from all other classes, why would it matter if they existed or not? It would have no effect on the program's operation what they were called, or how they were broken up. --- So for example if you had a "shift(int gear)" function, it could be called "changeGear(int gear)" in another class, and the effect would be the same. Or you could have a car with only one gear and no functions to change it. Since the functions can't be called by any other class, it doesn't matter. -- Abstract protected would work for when you need to call the functions in subclasses.
Chad Okere
Yes that is the whole point. I know they can be called different things but I don't want them to be. Imagine having 10 car classes all using different names internally for the same function. Yes you can argue that it doesn't matter how someone else implements it, which is true. But when writing the code for yourself it would help to have them all use the same method names. This applies even more so when someone new joins the project, doesn't know anything, and ends up inadvertently changing the naming conventions that were used previously.
John Baker
So you could argue that what you are trying to achieve is coding-standard enforcement rather than code-reuse - using javac to enforce coding-standards. [not necessarily a bad idea I don't think: using the rule that compilation errors are easier to fix than logic errors].However: if this is the case - personally I would go with TofuBeer's idea - use junit to control this: it might make things cleaner and easier to maintain.
monojohnny
Hmm, if you really want you can use Java annotations and a custom build step with an annotation processor. I wrote another answer with more information: http://stackoverflow.com/questions/1986191/java-is-there-a-way-to-you-enforce-a-implementation-of-private-methods/1987313#1987313
Chad Okere
+1  A: 

Create an abstract base class with a method marked final that describes the common flow that includes your private methods. Marking it as final means that it can't be extended by subclasses and thus the business logic is enforced as long as your calling code utilizes it. Extension points can be created by marking methods as protected. For example say you have a class that represents a retail store.

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);

}
bpapa
+1  A: 

The "throw MethodNotImplementedException();" might be a useful construct.

Hamish Grubijan
+2  A: 

Create an outline 'common' class, with all your private methods on them.

Then create your 5 or 6 classes , each which have a field on there of type 'common'. You won't be able to call the private methods of course (but you say these are really internal to the class) - you'll have to advertise some public methods to alter state as well of course.

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

public class myclass1 { 
    common commonMethods;
}

public class myclass2 { 
    common commonMethods;
}

or even (assume 'common' is defined as above):

public class template {
    common commonMethods;
}

public class myclass1 extends template {
...
}

So you get a (package-protected) 'commonMethods' field for 'free' on each of 5 or 6 subclasses.

After subsequent discussion on this thread, it appears the author doesn't actually want to share logic : just method signatures essentially , so this answer doesn't fit with that requirement.

monojohnny
+3  A: 

There is no way to enforce it at compile time, but you can write a unit test or a simple program to test for the existence of the methods using reflection.

I assume you are doing this to make the classes consistent for aesthetics/design reasons. If you are doing it for some other reason you should really use the abstract protected way others are suggesting.

Here is some code to get you started on such a tool/unit tests (you should improve the error messages at the very least, and I would really suggest unit tests rather then what I have here):

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);
    }
}
TofuBeer
+1  A: 

If abstract protected really isn't protected enough, I wonder what the concern is. In any case, an alternative similar to monojohnny's would be to use the strategy pattern. This ensures that:

  • derived classes must define the behavior
  • derived classes can't access the behavior after defining it
  • instances can't access one another's behavior

E.g., with apologies for borrowing the car metaphor despite no automotive chops:

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());
    }
}
Michael Brewer-Davis
+1  A: 

Take a look at XDepend, it uses reflection to create a database based on your compiled code.

http://www.xdepend.com

It's aimed at software architects who wish to be able to quickly check potentially large libraries of compiled code for potential problem areas. It has inbuilt reports and visualization for such things as relationships between classes, cyclomatic complexity, coupling etc. etc.

In addition, it includes an inbuilt sql like query language "CQL" (for "code query language"). Using CQL you can define your own reports. You probably should be able to use it to define a report for violations of the rules you describe. Also, you can embed CQL queries directly into your code using annotations.

I haven't looked into it, but have used it's .NET equivalent 'NDepend', and it's a very cool tool.

Of course, you could also write your own custom tool which uses reflection to check your specific rules. XDepend may still be worth looking at though - it should be a lot more flexible.

Phil
Looks interesting. And pricey unfortunately.
John Baker
Yeah, it is particularly if you need to equip all your developers with a copy. It's aimed at software architects though, so the expectation is probably you'd only usually have a small number of copies.
Phil
+1  A: 

Is it possible to make all the classes inherit from the same base class?

If so, one thing you could consider would be at runtime in the base class's constructor use reflection to validate that the subclass is following the rules you describe, and throw an exception if it fails your validation rules.

The naive implementation of this test of course would have significant performance issues, so you'd have to be pretty clever about the way you implement the test.

For a start, the test should only be run once for all instances of a particular subtype T. So, you would have to cache the validation information somewhere. One way to do this would be to use some kind of static (global) hash table in the base class keyed on the type of each subtype.

You would also have to perform some kind of thread safe synchronization around this cache. What you really need to avoid on this is a performance hit for reads. What I've done in a similar case before was use a combination of the double check locking pattern and the use of an immutable hashtable so that you only take a performance hit for locking when attempting to write to the hashtable (i.e. when you create the first instance of a particular subtype T).

I'm actually not experienced in Java, what I describe, I implemented in .NET, which is why I can't provide you with a code example, but all the concepts should be easily transferable to Java - everything I mention is (AFAIK) available on both platforms.

Phil
+1  A: 

While the interface methods themselves must always be public, you could make the interface package private and keep all of your Car (for example) implementations in the same package.

package com.some.car.pkg;

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

Even though the methods are public, it doesn't matter since outside of the package com.some.car.pkg, Car is not visible. This way, all of your implementers would not be forced to extend an abstract class. The fact that you want common methods means truly private isn't the real solution, and IMHO, you want an interface, since it sounds like in your case an abstract class isn't quite right as there is no shared logic.

My 2 cents.

Joshua McKinnon
This sounds like a clean way of doing things to me: and it seems to satisfy both requirements: implementers will have to write methods with the required signatures from the interface at design-time, and the package structure keeps the whole class and all its methods away from other classes.Sounds also like there is no real shared logic between the classes here as well: so I agree with abstract classes not being an exact fit.
monojohnny
A: 

Here's an idea: write a simple text parser to check for the existence of the methods. Include it as a task in Ant. As long as you are insisting on some form of coding standard, some simple text-matching should do it, ie, simply look for the formatted signature in the required source files.

Perry Munger
A: 

In a comment you wrote "Yes that is the whole point. I know they can be called different things but I don't want them to be."

Now, some people might just say "that's impossible" but like most things in programming, it's not actually impossible, it's just a lot of work.

If you really want to do this, you can create a custom Java Annotation for your class and then write an Annotation processor and call apt as part of your build process.

Like I said a lot of work, but it might be worthwhile if you want to learn how Annotations work.


Writing annotations is actually pretty simple. They work kind of like regular classes. For example, if you just want to mark a class for some reason you can create an empty or marker annotation like this

public @interface Car { }

Then in your Annotation Processor you can check to make sure Car has the right private methods.

I've written my own annotations, but I checked them at Runtime using the reflection API, rather then at build time. They are actually pretty easy.

Chad Okere