Reputation: 65
So I'm writing some code that involves extending a class I have previously written in which files are created and named using a constructor that takes in a name and a size of type long. In that original class, I verified within the constructor that the entered file name contained one "." character but did not require a specific extension on the file. For this new class that I am writing, I am requiring the name's extension be ".mp3".However, my compiler does not like verification before the super constructor.
This is my current code:
public class Song extends DigitalMedia{
private String artist;
private String album;
private String name;
private long size;
public Song(String aName, long aSize, String aArtist, String aAlbum){
super(aName, aSize);
setArtist(aArtist);
setAlbum(aAlbum);
}
Is there any way to verify that "aName" contains ".mp3" before I create that constructor?
Upvotes: 6
Views: 1034
Reputation: 5316
Code execution reaching the constructor
implies the object is live and now ready for initialization of its states
(fields).
Object of a class A.java
can also be called as an Object of super class of A.java
. Before class A.java
initilizes the state, its makes sense the objects inherits the properties and features from the super class. After super class does the initialization , the class A.java
gets the chance to does is initialization.
Constructor of super class is implicitly called if there is a no parameter constructor present in the super class else you need to call any one of the parameterized constructors of the super class explicitly.
What you wish to do if the condition fails in the constructor
? You have option of throwing an exception but still the object is created, you can verify the same by overriding the finalize()
method and checking the this
object. You may want to influence the garbage collector by invoking System.gc()
for the code execution reaching the finalize()
method sooner.
proposed solution
You should validate the parameters of constructor before invoking the constructor. If you want to encapsulate it in your class then you may opt to add a non private static method (you may wish to name it like getInstance()
)creating and returning the object of the class Song
. You can have your constructor as private in such a case. Note that this will make your class as non extendable, it is simply a design choice.
Upvotes: 2
Reputation: 33875
From an inheritance stand-point, a sub-class shouldn't really be more restrictive than it's super class.
But if you want to make the instantiation of the sub-class more restricted, you could make the constructor private
and provide a factory method that first does the validation.
public class Song extends DigitalMedia {
private String artist;
private String album;
private String name;
private long size;
private Song(String aName, long aSize, String aArtist, String aAlbum) {
super(aName, aSize);
setArtist(aArtist);
setAlbum(aAlbum);
}
public static Song makeSong(String aName, long aSize, String aArtist, String aAlbum) {
//... validation code
return new Song(aName, aSize, aArtist, aAlbum);
}
...
}
Instead of restricting the type itself, you use encapsulation to enforce the invariant.
Upvotes: 0
Reputation: 15146
An alternative solution would be to enforce your rules via built-in type checking.
You could create a MediaFormat
:
interface MediaFormat { }
A MusicFormat
which implements MediaFormat
, allowing you to specify which musical formats are supported:
enum MusicFormat implements MediaFormat {
MP3("mp3");
private final String format;
MusicFormat(String format) {
this.format = format;
}
@Override
public String toString() {
return format;
}
}
DigitalMedia
could then be composed of a MediaFormat
:
class DigitalMedia {
private final MediaFormat format;
private final String name;
public DigitalMedia(String name, MediaFormat format) {
this.name = name;
this.format = format;
}
}
Song
could accept a MusicFormat
:
class Song {
public Song(String name, MusicFormat format) {
super(name, format);
}
}
This will force users to use whatever is specified in MusicFormat
, avoiding all those nasty checks. You could then expose a String
method that returns name + "." + format
Upvotes: 1
Reputation: 281252
I can't say whether it's the best way to design your program, but you could call a validator method inside one of the super
arguments:
public Song(String aName, long aSize, String aArtist, String aAlbum){
super(validateName(aName), aSize);
setArtist(aArtist);
setAlbum(aAlbum);
}
private static String validateName(String name) {
if (whatever) {
throw new Whatever();
}
return name;
}
Upvotes: 3