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.
What should be at the top of inheritance tree of Decorator design pattern?
How to discriminate:
- non-abstract class - Only if it makes sense in your code to instantiate it in client code (also see: liskov substitution)
- abstract class or interface - most common case; This is when it doesn't make sense for client code to instantiate it; To distinguish between abstract class and interface: If you look through your code and find that all specializations have data in common, move it to the base class (otherwise, remain with the interface).
- abstract class and interface - if there are two cases when a part of your specializations have common code and a part don't, extract common code to separate class, and you end up with both cases.
My criteria is usually not derived from some pure rules that I respect to implement the decorator; Instead, I try to optimize for maintenance instead of purity.
You can also see that I do not particularly differentiate between abstract classes and interfaces; this is because in C++ there are no interfaces - only abstract classes (so the distinction feels a bit artificial).
Best Answer
As you mentioned, your options are
protected
andprivate
.protected
seems like a good default, but don't forget about the case where you don't want your sub classes to invoke a specific constructor. For example:In this (overly simplified) example, we guarantee that the values for
foo
,bar
, andXXX
are always specified and thatCalculatedProperty
andXXX
are always set.The private constructor allows us to have shared construction logic without code duplication. And, because it's private, sub-classes can't accidentally partially construct themselves.