looking for a specific use case where both a subclass and a class within the same package needs to access a protected field or method...
Well to me, such a use case is rather general than specific, and it stems from my preferences to:
- Start with as strict access modifier as possible, resorting to weaker one(s) only later as deemed necessary.
- Have unit tests reside in the same package as tested code.
From above, I can start designing for my objects with default access modifiers (I would start with private
but that would complicate unit testing):
public class Example {
public static void main(String [] args) {
new UnitTest().testDoSomething(new Unit1(), new Unit2());
}
static class Unit1 {
void doSomething() {} // default access
}
static class Unit2 {
void doSomething() {} // default access
}
static class UnitTest {
void testDoSomething(Unit1 unit1, Unit2 unit2) {
unit1.doSomething();
unit2.doSomething();
}
}
}
Side note in above snippet, Unit1
, Unit2
and UnitTest
are nested within Example
for simplicity of presentation, but in a real project, I would likely have these classes in separate files (and UnitTest
even in a separate directory).
Then, when a necessity arises, I would weaken access control from default to protected
:
public class ExampleEvolved {
public static void main(String [] args) {
new UnitTest().testDoSomething(new Unit1(), new Unit2());
}
static class Unit1 {
protected void doSomething() {} // made protected
}
static class Unit2 {
protected void doSomething() {} // made protected
}
static class UnitTest {
// ---> no changes needed although UnitTest doesn't subclass
// ...and, hey, if I'd have to subclass... which one of Unit1, Unit2?
void testDoSomething(Unit1 unit1, Unit2 unit2) {
unit1.doSomething();
unit2.doSomething();
}
}
}
You see, I can keep unit test code in ExampleEvolved
unchanged due to protected methods being accessible from the same package, even though accessing object is not a sub-class.
Less changes needed => safer modification; after all I changed only access modifiers and I did not modify what methods Unit1.doSomething()
and Unit2.doSomething()
do, so it is only natural to expect unit test code to continue run without modifications.
You can expose items that would otherwise have some kind of restricted access (i.e., private or protected) without writing a wrapper function by using the using
directive:
class base {
public:
base();
virtual ~base();
void do_something();
void do_something_else();
private:
// elided
};
class derived : private base {
public:
derived();
virtual ~derived();
using base::do_something();
};
In the above, the derived class exposes base::do_something()
as a public method, but not base::do_something_else()
.
Best Answer
Short answer: Yes
Longer answer:
Yes, but that shouldn't be interpreted as a suggestion to start by writing your classes with everything private; that approach implies class design by focusing on the implementation detail before you've settled on an interface.
One of the most important aspects to consider when designing a class is how it will be used; which involves thinking about your public methods before you start thinking about private/implementation details.
Furthermore, that approach is usually missing out on chances to ask yourself "How would I write a unit test for this class?" - which is an important question to ask even if you aren't actually writing unit tests. (Related: "What are the design principles that promote testable code?" )
So, once you have defined the public interface, then it is a good idea to default the rest to private because most of that will typically be gritty implementation detail which is of no concern to anything outside of the class.