Reputation: 3568
I need to add new features to my framework that look likes this:
interface firstInterface{}
abstract class ReadOnly extends Forward{}
class Reference extends ReadOnly implements firstInterface{}
The abstract class ReadOnly
is to limit the features from Forward
by throwing unsupportedaction
.
I now need to support those function but in another class (thus have both options).
My first step was,
class baseReference implements firstInterface{}
abstract class ReadOnly extends Forward{}
class Reference extends baseReference, Readonly{}
class Loading extends baseReference, Forward{}
this results in multiple inheritance. Need help with the new design without much code duplication.
Upvotes: 1
Views: 58
Reputation: 4143
Seems, you are confusing interface implementation with class implementation.
Let me answer your question, using text based UML class diagrams, instead of code. Please consider dots as blank empty space.
[1] Your framework, has an interface called "FirstInterface", and this interface, defines a method called "Load", maybe there are other methods or properties.
.....................................
..+-------------------------------+..
..|.........<<interface>>.........|..
..|........FirstInterface.........|..
..+-------------------------------+..
..|.[+].void Load()...............|..
..+-------------------------------+..
.....................................
Note that the "+" inside square brackets means that a function or property can be accesed as "public".
[2] Your framework has a class called "ForwardClass" that supports the "FirstInterface".
Therefore, this class has its own "Load" method implemented.
.....................................
..+-------------------------------+..
..|.........<<interface>>.........|..
..|........FirstInterface.........|..
..+-------------------------------+..
..|.[+].void Load()...............|..
..+-------------------------------+..
..................|..................
................/---\................
................|.O.|................
..................|..................
..+-------------------------------+..
..|...........<<class>>...........|..
..|.........ForwardClass..........|..
..+-------------------------------+..
..|.[+].void Load()...<<virtual>>.|..
..+-------------------------------+..
.....................................
Note, that in Java, unlike other languages, all methods are considered "virtual", and can be replaced, without specifying anything.
I will use the "virtual" text when a method is declared the first time, and "override" text, in the diagrams, when a method already exists, and its replaced.
[3] Now, The "ForwardClass" class its extended by the "ReadOnlyClass" class, that replaces the "Load" method, and, raises a exception, called "UnsupportedActionException", remember exceptions are a special kind of classes or objects.
The "ReadOnlyClass" class, also add some extra methods.
.....................................
..+-------------------------------+..
..|...........<<class>>...........|..
..|.........ForwardClass..........|..
..+-------------------------------+..
..|.[+].void Load()...<<virtual>>.|..
..+-------------------------------+..
..................|..................
..................^..................
................./.\.................
................/---\................
..................|...........................................................
..+---------------------------------+......+-------------------------------+..
..|............<<class>>............|...+--|.........<<exception>>.........|..
..|..........ReadOnlyClass..........|...|..|...UnsupportedActionException..|..
..+---------------------------------+...|..+-------------------------------+..
..|.[+].void Load()....<<override>>.|---+.....................................
..|.[+].void DoExtra()..<<virtual>>.|.........................................
..+---------------------------------+.........................................
..............................................................................
[4] Now, you want to extend the "ReadOnlyClass" class with the "LoadingClass". Let's suppouse it add some properties, or replaces the "DoExtra" method.
..............................................................................
..+---------------------------------+......+-------------------------------+..
..|............<<class>>............|...+--|.........<<exception>>.........|..
..|..........ReadOnlyClass..........|...|..|...UnsupportedActionException..|..
..+---------------------------------+...|..+-------------------------------+..
..|.[+].void Load()....<<override>>.|---+.....................................
..|.[+].void DoExtra()..<<virtual>>.|.........................................
..+---------------------------------+.........................................
..................|..................
..................^..................
................./.\.................
................/---\................
..................|..................
..+----------------------------------+..
..|............<<class>>.............|..
..|...........LoadingClass...........|..
..+----------------------------------+..
..|.[+].void DoExtra()..<<override>>.|..
..+----------------------------------+..
........................................
[5] Now, lets apply, the scenario, of your post.
Lets suppouse, you want that any "LoadingClass" object, also use the "Load" method of the "ForwardClass" parent class, ignoring the "Load" method of the "ReadOnlyClass" parent class, that generates an exception.
A potential solution, its to make a new protected method called with a name like "ConfirmedLoad", in the "ForwardClass". Lets add a box with the "#" character, to make clear its a "protected" method.
Move all the code of "Load" to "ConfirmedLoad", and then, make "Load" execute "ConfirmedLoad".
The inheritance of classes, continues the same, and other code that use this classes, are not affected, with the changes. Note that I did not put the "virtual" text to the "ConfirmedLoad", because, we are not interested in replacing this method.
............................................
..+---------------------------------------+..
..|...............<<class>>...............|..
..|.............ForwardClass..............|..
..+---------------------------------------+..
..|.[#].void ConfirmedLoad()..............|..
..|.[+].void Load()...........<<virtual>>.|..
..+---------------------------------------+..
.............................................
[6] Then, we can add a boolean "CanLoad" method, to the "ReadOnlyClass", that in this case, always return false, but, expect to be changed later. We also change the "Load" method in here, that calls the "CanLoad" function, and if the asnwer is false, the generate the exception.
............................................
..+---------------------------------------+..
..|...............<<class>>...............|..
..|.............ForwardClass..............|..
..+---------------------------------------+..
..|.[#].void ConfirmedLoad()..............|..
..|.[+].void Load()...........<<virtual>>.|..
..+---------------------------------------+..
..................|..................
..................^..................
................./.\.................
................/---\................
..................|..................
..+---------------------------------------+..
..|...............<<class>>...............|........+-------------------------------+..
..|.............ReadOnlyClass.............|.....+--|.........<<exception>>.........|..
..+---------------------------------------+.....|..|...UnsupportedActionException..|..
..|.[+].bool CanLoad()........<<virtual>>.|.....|..+-------------------------------+..
..|.[+].void Load()..........<<override>>.|..---+.....................................
..|.[+].void DoExtra()........<<virtual>>.|..
..+---------------------------------------+..
.............................................
[7] Now, in other to make the "Load" method be executed in any "LoadingClass" object, then, lets replace the "CanLoad" method, always returning true.
.............................................
..+---------------------------------------+..
..|...............<<class>>...............|..
..|.............ForwardClass..............|..
..+---------------------------------------+..
..|.[#].void ConfirmedLoad()..............|..
..|.[+].void Load()...........<<virtual>>.|..
..+---------------------------------------+..
.......................|..................
.......................^..................
....................../.\.................
...................../---\................
.......................|..................
..+---------------------------------------+..
..|...............<<class>>...............|........+-------------------------------+..
..|.............ReadOnlyClass.............|.....+--|.........<<exception>>.........|..
..+---------------------------------------+.....|..|...UnsupportedActionException..|..
..|.[+].bool CanLoad()........<<virtual>>.|.....|..+-------------------------------+..
..|.[+].void Load()..........<<override>>.|..---+.....................................
..|.[+].void DoExtra()........<<virtual>>.|..
..+---------------------------------------+..
.......................|..................
.......................^..................
....................../.\.................
...................../---\................
.......................|..................
..+---------------------------------------+..
..|...............<<class>>...............|..
..|.............LoadingClass..............|..
..+---------------------------------------+..
..|.[+].bool CanLoad().......<<override>>.|..
..+---------------------------------------+..
.............................................
[8] If you add other classes, that implement the "LoadInterface", and, also are subclasses of "ForwardClass", "ReadOnlyClass" or "LoadingClass" classes, that doesn't matter, because an interface can be supported several times, the interface only adds a "I expect these" stuff, not the real code itself.
.............................................
..+---------------------------------------+..
..|...............<<class>>...............|..
..|............FirstInterface.............|..
..+---------------------------------------+..
..|.[+].void Load().......................|..
..+---------------------------------------+..
.......................|......................
...................../---\....................
.....................|.O.|........................
.......................|..........................
.......................+-----------------------+..
.......................|.......................|..
.......................|.......................|..
..+---------------------------------------+....|..
..|...............<<class>>...............|....|..
..|.............ForwardClass..............|....|..
..+---------------------------------------+....|..
..|.[#].void ConfirmedLoad()..............|....|..
..|.[+].void Load()...........<<virtual>>.|....|..
..+---------------------------------------+....|..
.......................|.......................|..
.......................^.......................|..
....................../.\......................|..
...................../---\.....................|..
.......................|.......................|..
..+---------------------------------------+....|..
..|...............<<class>>...............|....|..
..|.............ReadOnlyClass.............|....|..
..+---------------------------------------+....|..
..|.[+].bool CanLoad()........<<virtual>>.|....|..
..|.[+].void Load()..........<<override>>.|....|..
..|.[+].void DoExtra()........<<virtual>>.|....|..
..+---------------------------------------+....|..
.......................|.......................|..
.......................^.......................|..
....................../.\......................|..
...................../---\.....................|..
.......................|.......................|..
..+---------------------------------------+....|..
..|...............<<class>>...............|....|..
..|.............LoadingClass..............|....|..
..+---------------------------------------+....|..
..|.[+].bool CanLoad().......<<override>>.|....|..
..+---------------------------------------+....|..
.......................|.......................|..
.......................^.......................|..
....................../.\......................|..
...................../---\.....................|..
.......................|.......................|..
..+---------------------------------------+....|..
..|...............<<class>>...............|----+..
..|...........BaseReferenceClass..........|.......
..+---------------------------------------+.......
..................................................
The "BaseReferenceClass" class implements, indirectly, the "FirstInterface" interface thru the "LoadingClass" class, but, also implements, again, directly, the same interface. That its OK with interfaces, but, is NOT with classes.
If, the "FirstInterface" interface, was an class (maybe abstract), the problem of multiple duplicated inheritance will cause a compilation error.
Cheers.
Upvotes: 0
Reputation: 31648
Favor Composition over inheritance. Wrap an implementation with a different implementation via delegation (the Adapter pattern)
public class ReadOnly implements Forward{
private Forward delegate;
public ReadOnly(Forward adaptee){
//check for null here if you want
this.delegate = adaptee;
}
public void loadFoo(Foo foo){
//invalid since this is read-only
//this is the exception mentioned in OP
throw new UnsupportedAction():
}
public Foo readFoo(){
//allowed return delegate's foo
return delegate.readFoo();
}
}
Upvotes: 1