I am using the Processing.org api - so i cant just change the classes in question.
Problem is simple, but i havent found an answer:
void drawStuff(PGraphics view) {
view.beginShape();
view.vertex(... lots of vertex calls / lines
}
void drawStuff(PShape view) {
view.beginShape();
view.vertex(... lots of vertex calls / lines
}
what i need is a way to combine them into one method, like:
void drawStuff(Object view) {
// how to cast to PShape and PGraphics
view.beginShape();
view.vertex(... lots of vertex calls /lines
}
the classes PShape and PGraphics have same/similar methods, at lest for the one i call, they are the same. But according to the Processing javadocs, PShape and PGraphics are both coming from java.lang.Object, so as far as i understand the dont share anything.
Like others pointed out in the comments of the OP, write a wrapper class/interface. The interface is the abstraction towards your code in which you don't want to know the actual implementation you're dealing with:
Start with defining the interface:
public interface PWrapper {
public void beginShape();
public void vertex();
}
Then, because of the unfortunate design in which PShape and PGraphics have nothing in common but Object, you'll need to implement a wrapper for each of these classes that implements your new interface. These wrappers are infact delegating their method calls to the appropriate methods of the wrapped object. For example, the wrapper for a PShape would be implemented like this:
public final class PShapeWrapper implements PWrapper {
private final PShape ps;
public PShapeWrapper (PShape ps){
this.ps = ps;
}
#Override
public void beginShape(){
ps.beginShape();
}
#Override
public void vertex(){
ps.vertex();
}
}
Then again in your code, define the method like this:
void drawStuff(PWrapper wrap) {
wrap.beginShape();
wrap.vertex();
}
As you can see, this method does not know what runtime object it's dealing with: it may be a PShapeWrapper (see above) or a PGraphicsWrapper (not posted). Even better: it may be any class that implements PWrapper but doesn't exist yet, so this is a maintainability plus.
This design pattern is called "Adapter".
Related
I design my game application and face some troubles in OOP design.
I want to know some patterns which can help me, because java have not any multiple extends option. I will describe my problem below, and also explain why multiple interface doesn't help me at all. Lets go.
What we want is "class is set of features". By feature I mean construction like:
field a;
field b;
field c;
method m1(){
// use, and change fields a,b,c;
}
method m2(){
// use, and change fields a,b,c;
}
//etc
So, basically the feature is a set of methods and corresponding fields. So, it's very close to the java interface.
When I talk that class implemets "feature1" I mean that this class contains ALL "feature needed" fields, and have realisation of all feature related methods.
When class implements two features the tricky part begins. There is a change, that two different features contains similar fields (names of this fields are equal). Let the case of different types for such fields will be out of scope. What I want - is "feature naming tolerance" - so that if methodA() from feature A change the field "common_field", the methodB from feature B, that also use "common_field" as field will see this changes.
So, I want to create a set of features (basically interfaces) and their implementations. After this I want to create classes which will extends multiple features, without any copy-paste and other crap.
But I can't write this code in Java:
public static interface Feature1 {
public void method1();
}
public static interface Feature2 {
public void method2();
}
public static class Feature1Impl implements Feature1 {
int feature1Field;
int commonField;
#Override
public void method1() {
feature1Field += commonField;
commonField++;
}
}
public static class Feature2Impl implements Feature2 {
int feature2Field;
int commonField;
#Override
public void method2() {
commonField++;
}
}
public static class MyFeaturedClass extends Feature1Impl, Feature2Impl implements Feature1, Features2 {
}
So, as you can see the problem are really complex.
Below I'll describe why some standart approaches doesn't work here.
1) Use something like this:
public static class MyFeaturesClass implements Feature1,Feature2{
Feature1 feature1;
Feature2 feature2;
#Override
public void method2() {
feature2.method2();
}
#Override
public void method1() {
feature1.method1();
}
}
Ok, this is really nice approach - but it does not provide "feature field name tolerance" - so the call of method2 will not change the field "commonField" in object corresponding the feature1.
2) Use another design. For what sake you need such approach?
Ok. In my game there is a "unit" concept. A unit is MOVABLE and ALIVE object.
Movable objects has position, and move() method. Alive objects has hp and takeDamage() and die() methods.
There is only MOVABLE objects in my game, but this objects isn't alive.
Also, there is ALIVE objects in my game, but this objects isn't movable (buildings for example).
And when I realize the movable and alive as classes, that implements interfaces, I really don't know from what I should extends my Unit class. In both cases I will use copy-paste for this.
The example above is really simple, actually I need a lot of different features for different game mechanics. And I will have a lot of different objects with different properties.
What I actually tried is:
Map<Field,Object> fields;
So any object in my game has such Map, and to any object can be applied any method. The realization of method is just take needed fields from this map, do its job and change some of them. The problem of this approach is performance. First of all - I don't want to use Double and Interger classes for double and int fields, and second - I want to have a direct accsess to the fields of my objects (not through the map object).
Any suggestions?
PS. What I want as a result:
class A implements Feature1, Feature2, Feature3, Feature4, Feature5 {
// all features has corresponding FeatureNImpl implementations;
// features 1-2-3 has "shared" fields, feature 3-4 has, features 5-1 has.
// really fast implementation with "shared field tolerance" needed.
}
One possibility is to add another layer of interfaces. XXXProviderInterface could be defined for all possible common fields, that define a getter and setter for them.
A feature implementation class would require the needed providers in the constructor. All access to common fields are done through these references.
A concrete game object class implementation would implement the needed provider interfaces and feature interfaces. Through aggregation, it would add the feature implementations (with passing this as provider), and delegate the feature calls to them.
E.g.
public interface Feature1 {
void methodF1();
}
public interface Feature2 {
void methodF2();
}
public interface FieldAProvider {
int getA();
void setA(int a);
}
public class Feature1Impl implements Feature1 {
private FieldAProvider _a;
Feature1Impl(FieldAProvider a) {
_a = a;
}
void methodF1() {
_a.setA(_a.getA() * 2);
}
}
// Similar for Feature2Impl
public class GameObject implements Feature1, Feature2, FieldAProvider
{
int _fieldA;
Feature1 _f1;
Feature2 _f2;
GameObject() {
_f1 = new Feature1Impl(this);
_f2 = new Feature2Impl(this);
}
int getA() {
return _fieldA;
}
void setA(int a) {
_fieldA = a;
}
void methodF1() {
_f1.methodF1();
}
void methodF2() {
_f2.methodF2();
}
}
However, I don't think this is an optimal solution
I am newbie to java, and developing a real life project. I have many methods and about 2500 lines of code thus far. Many of the methods are slightly different(usually a difference of mere a single identifier) due to which i have to copy the code again and again with slight changes.
What i want is to pass a method as parameter to another method, I've gone through lambda expressions
but i could not find it enough appealing, off-course due to my own conceptual shortcomings. because it tells to define functional interface of each method to be passed. but as per my thoughts it would not give me a generic code so that i would be able to simply add some other Tables in future.
i am putting a piece of code to demonstrate and better explain my problem.
if(houseTabPanel.getComponentCount()==0){
houseTableDb();
}
if(isSelected){
selection(houseTable);
}
else {
houseTable.setColumnSelectionAllowed(false);
houseTable.setRowSelectionAllowed(false);
houseTable.setCellSelectionEnabled(false);
Rselection(houseTable);
}
now i have different methods named houseTableDb() , plotTableDb() , adminTableDb() etc.
i want to make a method of this piece of code and pass plotTableDb() etc as parameter..
something like...
public void genericMethod(JPanel p, JTable t, some method reference to use instead of houseTableDb){}
pardon me if am not descriptive enough.. any response would be truly appreciated by core of the heart.
Provided that all of these methods have the same signature you can define an interface with a single method with that signature (return value, parameter list). Then you write classes implementing the method, one for each method's implementation. For passing the method, you create an object of that class and pass the object. The call to the actual method is replaced by the call to the method defined in the interface.
interface Callee {
void meth();
}
class MethOne implements Callee {
public void meth(){...}
}
void caller( Callee callee ){
callee.meth();
}
Callee ofOne = new MethOne();
caller( ofOne );
But to avoid all this hazzle: that's why lambdas have been added...
You can do like this :
public void genericMethod(JPanel p, JTable t, TableDbCallBack tableDb)
{
if(p.getComponentCount()==0)
{
tableDb.run();
}
if(isSelected)
{
selection(t);
}
else
{
t.setColumnSelectionAllowed(false);
t.setRowSelectionAllowed(false);
t.setCellSelectionEnabled(false);
Rselection(t);
}
}
usage :
genericMethod(p, t, new HouseTableDb());
genericMethod(p, t, new AdminTableDb());
Implementation :
public interface TableDbCallBack extends Runnable {}
public class HouseTableDb implements TableDbCallBack
{
#Override
public void run()
{
// Whatever it should do
}
}
public class AdminTableDb implements TableDbCallBack
{
#Override
public void run()
{
// Whatever it should do
}
}
Am I using a feature of Java 8 or misusing it?
Refer the code and explanation below to know as to why it was chosen to be like this.
public interface Drawable {
public void compileProgram();
public Program getProgram();
default public boolean isTessellated() {
return false;
}
default public boolean isInstanced() {
return false;
}
default public int getInstancesCount() {
return 0;
}
public int getDataSize();
public FloatBuffer putData(final FloatBuffer dataBuffer);
public int getDataMode();
public boolean isShadowReceiver();
public boolean isShadowCaster(); //TODO use for AABB calculations
default public void drawDepthPass(final int offset, final Program depthNormalProgram, final Program depthTessellationProgram) {
Program depthProgram = (isTessellated()) ? depthTessellationProgram : depthNormalProgram;
if (isInstanced()) {
depthProgram.use().drawArraysInstanced(getDataMode(), offset, getDataSize(), getInstancesCount());
}
else {
depthProgram.use().drawArrays(getDataMode(), offset, getDataSize());
}
}
default public void draw(final int offset) {
if (isInstanced()) {
getProgram().use().drawArraysInstanced(getDataMode(), offset, getDataSize(), getInstancesCount());
}
else {
getProgram().use().drawArrays(getDataMode(), offset, getDataSize());
}
}
default public void delete() {
getProgram().delete();
}
public static int countDataSize(final Collection<Drawable> drawables) {
return drawables.stream()
.mapToInt(Drawable::getDataSize)
.sum();
}
public static FloatBuffer putAllData(final List<Drawable> drawables) {
FloatBuffer dataBuffer = BufferUtils.createFloatBuffer(countDataSize(drawables) * 3);
drawables.stream().forEachOrdered(drawable -> drawable.putData(dataBuffer));
return (FloatBuffer)dataBuffer.clear();
}
public static void drawAllDepthPass(final List<Drawable> drawables, final Program depthNormalProgram, final Program depthTessellationProgram) {
int offset = 0;
for (Drawable drawable : drawables) {
if (drawable.isShadowReceiver()) {
drawable.drawDepthPass(offset, depthNormalProgram, depthTessellationProgram);
}
offset += drawable.getDataSize(); //TODO count offset only if not shadow receiver?
}
}
public static void drawAll(final List<Drawable> drawables) {
int offset = 0;
for (Drawable drawable : drawables) {
drawable.draw(offset);
offset += drawable.getDataSize();
}
}
public static void deleteAll(final List<Drawable> drawables) {
drawables.stream().forEach(Drawable::delete);
}
}
public interface TessellatedDrawable extends Drawable {
#Override
default public boolean isTessellated() {
return true;
}
}
public interface InstancedDrawable extends Drawable {
#Override
default public boolean isInstanced() {
return true;
}
#Override
public int getInstancesCount();
}
public class Box implements TessellatedDrawable, InstancedDrawable {
//<editor-fold defaultstate="collapsed" desc="keep-imports">
static {
int KEEP_LWJGL_IMPORTS = GL_2_BYTES | GL_ALIASED_LINE_WIDTH_RANGE | GL_ACTIVE_TEXTURE | GL_BLEND_COLOR | GL_ARRAY_BUFFER | GL_ACTIVE_ATTRIBUTE_MAX_LENGTH | GL_COMPRESSED_SLUMINANCE | GL_ALPHA_INTEGER | GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH | GL_ALREADY_SIGNALED | GL_ANY_SAMPLES_PASSED | GL_ACTIVE_SUBROUTINE_UNIFORM_MAX_LENGTH | GL_ACTIVE_PROGRAM | GL_ACTIVE_ATOMIC_COUNTER_BUFFERS | GL_ACTIVE_RESOURCES | GL_BUFFER_IMMUTABLE_STORAGE;
int KEEP_OWN_IMPORTS = UNIFORM_PROJECTION_MATRIX.getLocation() | VS_POSITION.getLocation();
}
//</editor-fold>
private FloatBuffer data;
private Program program;
private final float width, height, depth;
public Box(final float width, final float height, final float depth) {
this.width = width;
this.height = height;
this.depth = depth;
data = generateBox();
data.clear();
}
#Override
public void compileProgram() {
program = new Program(
new VertexShader("data/shaders/box.vs.glsl").compile(),
new FragmentShader("data/shaders/box.fs.glsl").compile()
).compile().usingUniforms(
UNIFORM_MODEL_MATRIX,
UNIFORM_VIEW_MATRIX,
UNIFORM_PROJECTION_MATRIX,
UNIFORM_SHADOW_MATRIX
);
}
#Override
public int getInstancesCount() {
return 100;
}
#Override
public Program getProgram() {
return program;
}
#Override
public int getDataSize() {
return 6 * 6;
}
#Override
public FloatBuffer putData(final FloatBuffer dataBuffer) {
FloatBuffer returnData = dataBuffer.put(data);
data.clear(); //clear to reset data state
return returnData;
}
#Override
public int getDataMode() {
return GL_TRIANGLES;
}
#Override
public boolean isShadowReceiver() {
return true;
}
#Override
public boolean isShadowCaster() {
return true;
}
private FloatBuffer generateBox() {
FloatBuffer boxData = BufferUtils.createFloatBuffer(6 * 6 * 3);
//put data into boxData
return (FloatBuffer)boxData.clear();
}
}
First the steps on how I came to this code:
I started with the Drawable interface and each implementation having its own drawDepthPass, draw and delete methods.
Refactoring delete to a default method was easy, trivial and should not be wrong.
However to be able to refactor drawDepthPass and draw I needed access to whether a Drawable was tesselated and/or instanced, so I added the public (non-default) methods isTessellated(), isInstanced() and getInstancesCount().
Then I figured out it would be slightly cumbersome, as we programmers are lazy, to implement them in every Drawable.
As a consequence I added the default methods to Drawable, giving the behaviour of the most basic Drawable.
Then I figured that I am still lazy and do not want to manually implement it for the tessellated and instanced variants eithere.
So I created TessellatedDrawable and InstancedDrawable that provide default isTessellated() and isInstanced() respectively. And in InstancedDrawable I revoked the default implementation of getInstancesCount().
As a result I can have the following:
Normal Drawable: public class A implements Drawable
Tessellated Drawable: public class A implements TessellatedDrawable
Instanced Drawable: public class A implements InstancedDrawable
Tessellated and instanced Drawable: public class A implements InstancedDrawable, TessellatedDrawable.
Just to ensure you, this all compiles and runs fine, the implements InstancedDrawable, TessellatedDrawable gets handled perfectly by Java 8 as there is nowhere ever ambiguity on from which interface the functionality should come.
Now onto my own little OOP design assessment:
Every Drawable is in fact a Drawable, so Collection<Drawable> will not break.
It is possible to group all TessellatedDrawable and/or InstancedDrawable, irrelevant of how exactly it is implement.
Other thoughts I had:
Use a more conventional, layered approach, however I disregarded that as it would end up in:
abstract class AbstractDrawable
class Drawable extends AbstractDrawable
class TessellatedDrawable extends AbstractDrawable
class InstancedDrawable extends AbstractDrawable
class InstancedTessellatedDrawable extends AbstractDrawable
I have also considered a Builder Pattern, however that is a pattern to be used when you are creating a lot of unique instances of a certain object, and that is not what we are doing here, neither is this about the constructor of the object.
So the first and final question was: Am I using a feature of Java 8 or misusing it?
First, if it works, and it does what you want to do, and there's no danger of something breaking in the future, it doesn't make sense to say you're misusing it. After all, it got the job done, right? Features like default methods and static methods were added to interfaces with particular goals in mind, but if they help you achieve other goals, either that's creative use of a new feature or a gross and dirty hack. :-) To a certain extent it's a matter of taste.
With that perspective in mind, what I look for in APIs, and what I try to do when designing APIs, is to distinguish clients of an API from implementors of an API. A typical client, or user, of an API gets a reference of some interface type from somewhere and calls methods on it to make stuff happen. An implementor provides implementations for methods defined in interfaces, overrides methods, and (if subclassing) calls superclass methods. Often, the methods intended to be called by clients are different from those intended to be called from subclasses.
It seems to me that these concepts are being mixed in the Drawable interface. Certainly, clients of a Drawable will do things like call the draw or drawDepthPass methods on them. Great. But looking at the default implementation of drawDepthPass, it gets some information using isTessellated and isInstanced methods, and then uses these to choose a Program and call methods on it in a particular way. It's fine for these bits of logic to be encapsulated within a method, but in order for it to be done in a default method, the getters have to be forced into the public interface.
I might be wrong about your model, of course, but it seems to me that this kind of logic is more suited for an abstract superclass and subclasser relationship. The abstract superclass implements some logic that handles all Drawables, but it negotiates with the particular Drawable implementations with methods like isTesselated or isInstanced. In an abstract superclass, these would be protected methods that subclasses are required to implement. By putting this logic into default methods of an interface, all of these have to be public, which clutters up the client interface. The other methods that seem similar are getDataMode, isShadowReceiver, and isShadowCaster. Are clients expected to call these, or are they logically internal to the implementation?
What this highlights is that, despite the addition of default methods and static methods, interfaces are still oriented toward clients, and less toward supporting subclasses. The reasons are as follows:
Interfaces have only public members.
Abstract classes can have protected methods for subclasses to override or call.
Abstract classes can have private methods to enable implementation sharing.
Abstract classes can have fields (state) which can be protected to share state with subclasses, or usually private otherwise.
Abstract classes can have final methods that enforce certain behavior policies on subclasses.
Another issue I note with the Drawable interface family is that it uses the ability of default methods to override each other to allow some simple mixins to the implementation classes like Box. It is kind of neat that you can just say implements TessellatedDrawable and avoid the pesky overriding of the isTesselated method! The problem is that this now becomes part of the implementation class's type. Is it useful for the client to know that a Box is also a TessellatedDrawable? Or is this just a scheme for making the internal implementation cleaner? If it's the latter, it might be preferable these mixin interfaces like TessellatedDrawable and InstancedDrawable not be public interfaces (i.e., package private).
Note also that this approach clutters up the type hierarchy, which can make code more confusing to navigate. Usually a new type is a new concept, but it seems heavyweight to have interfaces that merely define default methods returning boolean constants.
A further point in this vein. Again, I don't know your model, but the characteristics being mixed in here are very simple: they're just boolean constants. If there's ever a Drawable implementation that, say, starts off not being instanced and later can become instanced, it can't use these mixin interfaces. The default implementations are really quite restricted in what they can do. They can't call private methods or inspect fields of an implementation class, so their use is quite limited. Using interfaces this way is almost like using them as marker interfaces, with a tiny addition of being able to call a method to get the characteristic, instead of using instanceof. There doesn't seem to be much use beyond this.
The static methods in the Drawable interface seem mostly reasonable. They're utilities that seem client-oriented, and they provide reasonable aggregations of logic provided by the public instance methods.
Finally, there are a few points about the model that seem odd, though they're not directly related to the use of default and static methods.
It seems like a Drawable has-a Program, as there are instance methods compileProgram, getProgram, and delete. Yet the drawDepthPass and similar methods require the client to pass in two programs, one of which is selected depending on the result of the boolean getters. It's not clear to me where the caller is supposed to choose the right Programs.
Something similar is going on with the drawAll methods and the offset value. It seems like in a list of Drawables, they have to be drawn using particular offsets based on each Drawable's data size. Yet what is apparently the most fundamental method, draw, requires the caller to pass in an offset. This seems like a big responsibility to push onto the caller. So perhaps the offset stuff really belongs within the implementation as well.
There are a couple methods that take a List of drawables and call stream() and then forEach() or forEachOrdered(). This isn't necessary, as List has a forEach method on it, inherited from Iterable.
I think it's great to explore how this new stuff can be used. It's new enough that a commonly accepted style hasn't yet emerged. Experiments like this, and this discussion, help to develop that style. On the other hand, we also need to be careful not to use these shiny new features just because they're new and shiny.
I'm working on an application in which I have two fairly similar object classes whose fields need to be normalized. Many of the fields that need to be normalized are shared by both of these classes, but there are some that pertain only to one or the other.
I was thinking to create an interface with getters and setters for all of the fields that need to be normalized, that way I could pass both objects to the same class and access the fields / set the normalized values via the interface methods. Would this be considered bad convention?
Below is simplified example-- the objects I am normalizing will only ever be read from once the normalization is completed. Thanks in advance!
class A implements C{
T x;
T y;
T z;
...
}
class B implements C{
T x;
T y;
T k; // no 'z', above has no k
....
}
interface C {
public T getX();
public void setX(T x);
public T getY();
public void setY(T y);
public T getZ();
public void setZ(T z);
public T getK();
public void setK(T k);
}
If the code is properly documented saying A does not support
public T getK();
public void setK(T k);
and B does not support
public T getZ();
public void setZ(T z);
then I think you can go ahead with this design.
And, also construct UnsupportedOperationException with the specified detail message for the classes that doesn't support some of the methods of C. For example,
class A implements C{
T x;
T y;
T z;
...
public T getK(){
throw new UnsupportedOperationException("YOUR MESSAGE");
}
}
Isn't implementing an interface and providing an empty implementation a bad design issue? though you document it, it goes against the concept of interface and is inconsistent as you may have an empty implementation of one method in one class, and another implementation in another class and the code will become inconsistent in the long run, making it unsafe.. consider this
interface iSample {
void doThing1();
void doThing2();
void doThing3();
}
class sClass1 implements iSample {
void doThing1() { //doThing1 code }
void doThing2() { //doThing2 code }
void doThing3() { } // empty implementation
}
class sClass2 implements iSample {
void doThing1() { //doThing1 code }
void doThing2() { } // empty implementation
void doThing3() { //doThing2 code }
}
class Test {
public static void main (String[] args) {
testing(new sClass1());
testing(new sClass2());
}
public void testing(iSample s) {
// you would have no idea here which object has omitted which method.
s.doThing1();
s.doThing2();
s.doThing3();
}
as stated above you would have no idea which object has omitted which method and inconsistency prevails.
Well, based on your description, you would have empty methods inside both of your classes because you won't need them. class A would leave getK and setK unimplemented, and class B would do the same with getZ and setZ.
In this case it might be best to use a parent class that has x and y, and leave the implementation of z and k local to class A and class B, respectively.
Highly similar classes?
This sounds like a really good time to design for inheritance. Note that designing for inheritance should be a really deliberate decision ... because there's a right way to do it which will make your API a joy to use and a wrong way which can make your API a hassle to use.
You can also use an interface-based type system as you are suggesting. This has the advantage of being applicable to classes that may not otherwise be related.
Or you can do both.
I suggest that you capture the essence of the relationship in your classes and describe that as the contract for your interface-based type system.
Then, I suggest that you produce a skeletal implementation of your contract in an abstract skeletal implementation class. Your concrete classes can inherit from your skeletal implementation and, if done well, will inherit much of the behavior and state that describes the essence of your contract.
Note that you should use your interface as the type designation for all your objects, much like we do with the Java Collections API. It is not encouraged to declare a parameter type as void myFunc(HashMap m); the best practice is to declare void myFunc(Map m). In the latter case, Map represents the interface-based type system for all the different implementors of the Map contract.
I have 2 classes that perform a very similar task, but require different data types passed to them in order to perform those functions.
They both ultimately write to files and have expose a single public method: write() using the constructor for simple dependency injection.
This is where they differ - 1 class accepts a single object of a specific type, while the other accepts an array of that object type.
Is this a valid case for polymorphism? I think it can be but tehcnically should not?
How is this situation to be correctly handled i.e. 2 or more classes which perform a very similar function, but in a slightly different way and crucially, require different data types passed in as dependencies?
You need overloaded methods in this case. One which works with single object and other with a number of objects. They should be in the same class.
Here is an easy-to-remember way of when to use what:
1. Overloading is when you need to do the same thing with different data
2. Overriding is when you need to do the same thing with the same data in a different way
public class FileWriter {
public void write(File from){ // single file
// magic logic
}
public void write(File... from){ // multiple files using varargs
// magic logic
}
}
If you only have two Write methods, one taking a single object and the other taking a List of objects -> I would put both methods on the same class.
If you have one Write for each type, I would go for generics.
Introducing a base class wouldn't be my first choice, better to extract the general stuff into another class and use it from different classes (has-a instead of is-a).
Polymorphism is only useful if you have the same method signature but need to do stuff in different ways.
Hard to answer without a particular code sample, but the scenario you've presented fits something similar to a decorator pattern:
class X
{
public void doSomething(int number) { ... }
};
class XForCollections
{
public XForCollections(X x) { ... }
public void doSomething(int[] numbers) { ... }
};
Note, that it's not really a decorator, as XForCollection doesn't inherit X.
Use an abstract generic superclass with the common stuff.
If you want WriterA that writes an argument of type ArgA, and WriterB that writes an argument of type ArgB, you'll make
an abstract Writer<T> with all of the common stuff in it, and an abstract method such as public void write(T arg)
WriterA that extends Writer<ArgA>
WriterB that extends Writer<ArgB>
Say you have this:
class A{
void write(int a){}
}
class B{
void write(int[] a){}
}
Since you say the implementations for those methods vary deeply between each other, then varargs probably wouldn't be a suitable option. To simplify things, do this::
class WriteStuff{
void write(int a){}
void write(int[] a){}
}
This would let you attain a higher level of cohesion for your classes. Polymorphism isn't really necessary here.
Then again, it's really too little information to go on with. You should probably write up some example code.
Polymorphism – means the ability of a single variable of a given type to be used to reference objects of
different types, and automatically call the method that is specific to the type of object the variable references. In a
nutshell, polymorphism is a bottom-up method call. The benefit of polymorphism is that it is very easy to add new
classes of derived objects without breaking the calling code that uses the polymorphic classes or interfaces. When you send a message to an object even though you
don’t know what specific type it is, and the right thing happens, that’s called polymorphism. The process used by
object-oriented programming languages to implement polymorphism is called dynamic binding.
Example:
Launcher
private void init() {
//client or calling code
double dim = 5.0; //i.e. 5 meters radius or width
List<Shape> listShapes = new ArrayList<Shape>(20);
Shape s = new Circle();
listShapes.add(s); //add circle
s = new Square();
listShapes.add(s); //add square
getTotArea (listShapes,dim); //returns 78.5+25.0=103.5
//Later on, if you decide to add a half circle then define
//a HalfCircle class, which extends Circle and then provide an
//area(). method but your called method getTotArea(...) remains
//same.
}
/** called method: method which adds up areas of various
** shapes supplied to it.
**/
public double getTotArea(List<Shape> listShapes, double dim){
Iterator<Shape> it = listShapes.iterator();
double totalArea = 0.0;
//loop through different shapes
while(it.hasNext()) {
Shape s = (Shape) it.next();
totalArea += s.area(dim); //polymorphic method call
}
return totalArea ;
}
}
Shape
public abstract class Shape {
protected abstract double area(double dim);
}
Square
public class Square extends Shape{
#Override
protected double area(double dim) {
return dim*dim;
}
}
Circle
public class Circle extends Shape{
#Override
protected double area(double dim) {
return Math.PI*dim*dim;
}
}