I have created a base interface which is implemented by some objects and I also have an array of interfaces which given a string return the objects mentioned. (a bit difficult to explain, better look the code :D) Then I want to pass this to the global object through some overloaded methods (at the beginning looked super clever, but it now seems technically impossible) Could I get any closer to what I want?
interface Stats { }
public class ObjectA implements Subscriber.Stats { // MORE THINGS }
public class ObjectB implements Subscriber.Stats { // MORE THINGS }
// MORE OBJECTS
This is the second interface which transforms a String into one of the classes from above
public interface Parser<T extends Stats> {
T parse(String data);
}
Now I have an array of implementations of the this interface I want to give me different results (ObjectA, ObjectB, ObjectC ..)
private final Parser<Stats>[] parsers = new Parser[] {
new Parser() {
#Override
public Stats parse(String data) {
return new ObjectA();
}
},
new Parser() {
#Override
public Stats parse(String data) {
return new ObjectB();
}
}
};
Now comes the "clever" part where I want to make something that may not be possible.
If I loop the array of parsers and each position gives me ObjectA, ObjectB due to Polymorphism I could call an overloaded method of a class with a signature like push(ObjectA) push(ObjectB), right??... Well this obviously doesn't work but is there any strategies I could use to accomplish this?
The loop would be:
for (int i = 0; i < operations.length; i++) {
dataHolder.push(parsers[i].parse(operations[i].getResult()));
}
EDITED
The problem is the method T parse (String value) is treated as if it returns Stats and not T extends Stats therefore when I call push it says there is no push(Stats) method
If I got it correctly, your dataHolder interface looks like this:
public interface DataHolder {
void push(ObjectA a);
void push(ObjectB b);
}
In that case really your loop cannot benefit from the overloaded methods, because at cimpile time, it only knows about parsers of Stats.
To achieve your goal you need to use the visitor pattern, and update your Stats hierarchy like this:
public interface Stats {
void accept(DataHolder holder);
}
public class ObjectA implements Stats {
void accept(DataHolder holder) {
holder.push(this); // this is ObjectA, so push(ObjectA) is used
}
}
public class ObjectB implements Stats {
void accept(DataHolder holder) {
holder.push(this); // this is ObjectB, so push(ObjectB) is used
}
}
Now if you do:
new Parser<Stat>().parse(input).accept(dataHandler);
It will use the propper overloaded push method (I didn't rewrite your loop, because I'm not sure if I unerstadt it properly, bu hopefully you can apply it yourself).
Sounds reasonable to me. Just try it.
String dataToParse = "wklhbglbwbgiwegbuwegbwe";
for(Parser p : parsers){
//The definition of each parser will be called and everything works.
System.out.println(p.parse(dataToParse));
}
Also you can just:
public void push(Object obj){
System.out.println(obj.getClass().getCardionalName());
//Or anything else you want to do with it.
}
Related
One of the reasons to consider the Visitor_pattern:
A practical result of this separation is the ability to add new operations to existing object structures without modifying those structures.
Assume that you don't have the source code of third party libraries and you have added one operation on related objects.
Since you don't have object, your elements (Third party classes) can't be modified to add Visitor.
In this case, double dispatch is not possible.
So which option is generally preferred?
Option 1: Extend one more inheritance hierarchy on top of third party class and implement pattern as show in picture with double dispatch?
For a given hierarchy of Class B which extends Class A, I will add
ElementA extends A
ElementB extends B
Now ConcreteElements are derived from ElementA instead of class A.
Cons: The number of classes will grow.
Option 2: Use Visitor class a central helper class and get the work done with single dispatch.
Cons: We are not really following Visitor patter as per UML diagram.
Correct if I am wrong.
You could combine a Wrapper and Visitor to solve your problems.
Using the wrapper to add a visit method allows you to increase the usability of these objects. Of course you get the full advantages (less dependency on the legacy classes) and disadvantages (additional objects) of a wrapper.
Here's a worked-up example in JAVA (because it is pretty strict, does not do double-dispatch by itself, and I'm quite familiar with it):
1) Your legacy Objects
Assuming you have your legacy objects Legacy1 and Legacy2which you cannot change, which have specific business methods:
public final class Legacy1 {
public void someBusinessMethod1(){
...
}
}
and
public final class Legacy2 {
public void anotherBusinessMethod(){
...
}
}
2) Prepare the Wrapper
You just wrap them in a VisitableWrapper which has a visit method that takes your visitor, like:
public interface VisitableWrapper {
public void accept(Visitor visitor);
}
With the following implementations:
public class Legacy1Wrapper implements VisitableWrapper {
private final Legacy1 legacyObj;
public Legacy1Wrapper(Legacy1 original){
this.legacyObj = original;
}
public void accept(Visitor visitor){
visitor.visit(legacyObj);
}
}
and
public class Legacy2Wrapper implements VisitableWrapper {
private final Legacy2 legacyObj;
public Legacy2Wrapper(Legacy2 original){
this.legacyObj = original;
}
public void accept(Visitor visitor){
visitor.visit(legacyObj);
}
}
3) Visitor, at the ready!
Then your own Visitors can be set to visit the wrapper like so:
public interface Visitor {
public void visit(Legacy1 leg);
public void visit(Legacy2 leg);
}
With an implementation like so:
public class SomeLegacyVisitor{
public void visit(Legacy1 leg){
System.out.println("This is a Legacy1! let's do something with it!");
leg.someBusinessMethod1();
}
public void visit(Legacy2 leg){
System.out.println("Hum, this is a Legacy 2 object. Well, let's do something else.");
leg.anotherBusinessMethod();
}
}
4) Unleash the power
Finally in your code, this framework would work like this:
public class TestClass{
// Start off with some legacy objects
Legacy1 leg1 = ...
Legacy2 leg2 = ...
// Wrap all your legacy objects into a List:
List<VisitableWrapper> visitableLegacys = new ArrayList<>();
visitableLegacys.add(new Legacy1Wrapper(legacy1));
visitableLegacys.add(new Legacy2Wrapper(legacy2));
// Use any of your visitor implementations!
Visitor visitor = new SomeLegacyVisitor();
for(VisitableWrapper wrappedLegacy: visitableLegacys){
wrappedLegacy.accept(visitor);
}
}
The expected output:
This is a Legacy1! let's do something with it!
Hum, this is a Legacy 2 object. Well, let's do something else.
Drawbacks:
Quite a lot of boilerplate. Use Lombok if you develop in Java.
Quite a lot of wrapper objects instances. May or may not be a problem for you.
You need to know the specific type of the objects beforehand. This implies you know their subtype, they aren't bundles in a List. If that's the case, you have no other option but to use reflection.
There should be a possibility to add new functionality to the classes of some hierarchy, without changing the base class interface. Kinds of possible behavior should be constant, while operations for different classes should execute differently.
The Visitor Pattern allows to concentrate all that operations in one class. There might be a lot of Concrete Element classes (from the diagram), but for each of them there will be implemented visit() method in Concrete Visitor class that will define his own algorithm.
Definition and implementation of method for each subclass of Element class:
public interface Visitor {
void visit(Element element);
}
public class ConcreteVisitor implements Visitor {
public void visit(Element element) {
// implementation
}
}
The Visitor Pattern is easily extended for new operations by implementing this interface by new class with his method implementation.
The following structure encapsulates the Element class:
public lass ObjectStructure {
private Element element;
// some methods
}
This ObjectStructure class could aggregate one or several instances of Element. Presentation that Visitor acts on:
public interface Element {
void accept(Visitor visitor);
}
And implementation of accept() method in the concrete entity:
public class ConcreteElement implements Element {
public void accept(Visitor visitor) {
visitor.visit();
}
}
Using of Visitor Pattern allows to save Element hierarchy from huge logical functionality or complicated configuration.
It is desirable to add the functionality to all the classes of hierarchy while defining a new Visitor subclasses. But there could be a problem: visit() should be overriden for every hierarchy type. To avoid this it's better to define AbstractVisitor class and all leave his all visit() method bodies empty.
Conclusion: using this pattern is good when class hierarchy of type Element keeps constant. If new classes add, it usually goes to considerable changes in classes of Visitor type.
My answer is very similar to Michael von Wenckstern's, with the improvements that we have a named accept method (more like the standard pattern) and that we handle unknown concrete classes -- there's no guarantee that at some point a concrete implementation we haven't seen before won't appear on the classpath.
My visitor also allows a return value.
I've also used a more verbose name for the visit methods -- including the type in the method name, but this isn't necessary, you can call them all visit.
// these classes cannot be modified and do not have source available
class Legacy {
}
class Legacy1 extends Legacy {
}
class Legacy2 extends Legacy {
}
// this is the implementation of your visitor
abstract class LegacyVisitor<T> {
abstract T visitLegacy1(Legacy1 l);
abstract T visitLegacy2(Legacy2 l);
T accept(Legacy l) {
if (l instanceof Legacy1) {
return visitLegacy1((Legacy1)l);
} else if (l instanceof Legacy2) {
return visitLegacy2((Legacy2)l);
} else {
throw new RuntimeException("Unknown concrete Legacy subclass:" + l.getClass());
}
}
}
public class Test {
public static void main(String[] args) {
String s = new LegacyVisitor<String>() {
#Override
String visitLegacy1(Legacy1 l) {
return "It's a 1";
}
#Override
String visitLegacy2(Legacy2 l) {
return "It's a 2";
}
}.accept(new Legacy1());
System.out.println(s);
}
}
First I had to made a few assumptions about the legacy code, since you didn't provide much details about it. Let's say I need to add a new method to Legacy without reimplementing everything. This is how I'll do it:
public interface LegacyInterface {
void A();
}
public final class LegacyClass implements LegacyInterface {
#Override
public void A() {
System.out.println("Hello from A");
}
}
First extends the "contract"
public interface MyInterface extends LegacyInterface {
void B();
}
And implement it in a "decorated" way
public final class MyClass implements MyInterface {
private final LegacyInterface origin;
public MyClass(LegacyInterface origin) {
this.origin = origin;
}
#Override
public void A() {
origin.A();
}
#Override
public void B() {
System.out.println("Hello from B");
}
}
The key point is MyInterface extends LegacyInterface: this is the guarantee the implementations will benefit from both the services from the legacy code and your personnal addings.
Usage
MyInterface b = new MyClass(new LegacyClass());
I think the best approach is the Option 1: Extend one more inheritance hierarchy on top of third party class and implement the visitor pattern with double dispatch.
The problem is the number of additional classes you need, but this can be resolved with a dynamic wrapper decorator.
The Wrapper Decorator is a way to add interface implementation, methods and properties to already existing obejcts: How to implement a wrapper decorator in Java?
In this way you need your Visitor interface and put there the visit(L legacy) methods:
public interface Visitor<L> {
public void visit(L legacy);
}
In the AcceptInterceptor you can put the code for the accept method
public class AcceptInterceptor {
#RuntimeType
public static Object intercept(#This WrappedAcceptor proxy, #Argument(0) Visitor visitor) throws Exception {
visitor.visit(proxy);
}
}
The WrappedAcceptor interface defines the method to accept a visitor and to set and retrieve the wrapped object
interface WrappedAcceptor<V> {
Object getWrapped();
void setWrapped(Object wrapped);
void accept(V visitor);
}
And finally the utility code to create the Wrapper around any obect:
Class<? extends Object> proxyType = new ByteBuddy()
.subclass(legacyObject.getClass(), ConstructorStrategy.Default.IMITATE_SUPER_TYPE_PUBLIC)
.method(anyOf(WrappedAcceptor.class.getMethods())).intercept(MethodDelegation.to(AcceptInterceptor.class))
.defineField("wrapped", Object.class, Visibility.PRIVATE)
.implement(WrappedAcceptor.class).intercept(FieldAccessor.ofBeanProperty())
.make()
.load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
WrappedAcceptor wrapper = (WrappedAcceptor) proxyType.newInstance();
wrapper.setWrapped(legacyObject);
If your library does not has accept methods you need to do it with instanceof. (Normally you do twice single-dispatching in Java to emulate double dispatching; but here we use instanceof to emulate double dispatching).
Here is the example:
interface Library {
public void get1();
public void get2();
}
public class Library1 implements Library {
public void get1() { ... }
public void get2() { ... }
}
public class Library2 implements Library {
public void get1() { ... }
public void get2() { ... }
}
interface Visitor {
default void visit(Library1 l1) {}
default void visit(Library2 l2) {}
default void visit(Library l) {
// add here instanceof for double dispatching
if (l instanceof Library1) {
visit((Library1) l);
}
else if (l instanceof Library2) {
visit((Library2) l);
}
}
}
// add extra print methods to the library
public class PrinterVisitor implements Visitor {
void visit(Library1 l1) {
System.out.println("I am library1");
}
void visit(Library2 l2) {
System.out.println("I am library2");
}
}
and now in any method you can write:
Library l = new Library1();
PrinterVisitor pv = new PrinterVisitor();
pv.visit(l);
and it will print to you "I am library1";
I have seen that one can use
ArrayList<Object> objectList = new ArrayList<Object>();
in order to generate a list that may contain different kinds of objects (such as object A and object B). I also have seen answers that state one can search what kind of objects are contained in that list by using
for (Object obj : objectList){
if(obj.getClass() == A.class){
doSomething();
}
}
However, its has been mentioned that this is not a very elegant approach. On the other hand, if I use an abstract class or an interface I need to have the same methods for object A and object B. For example if A.get() returns an integer, B.get() must also return an integer. But what I want is that the method making use of my objectList will do something different for different objects contained in the objectList. So A.get() may return an integer, B.get() may return a string.
So what I want to ask you guys is what is the best way to do this? Its not difficult to write a "hack", but I want to write good code.
Thanks.
If your method doSomething() is highly relying on the type of object, you could move it to those objects and use an interface.
public interface Foo {
void doSomething();
}
public class A implements Foo {
public void doSomething() {
// do something
}
}
for (Foo obj : objectList){
obj.doSomething();
}
How elegant this is strongly depends on what is done in doSomething(). If it is really different for each object, this approach might work. If it is similar, try identifying only the differences and encapsulate them in the interface like shown above.
Like this?
public class BaseClass {
public void method() {}
}
2
public class ChildOne extends BaseClass {
public void method() {
System.out.println("inside ChildOne");
}
}
3
public class ChildTwo extends BaseClass {
public void method() {
System.out.println("inside ChildTwo");
}
}
4
public class Client {
public static void main(String[] args) {
List<BaseClass> obj = new LinkedList<>();
obj.add(new ChildOne());
obj.add(new ChildTwo());
for (BaseClass b : obj) {
((BaseClass) b).method();
}
}
}
i currently have a problem with generics. i want to transfer existing java code into c#. can anybody tell me, how i can do following in c# ?
For example i have a class named module with a generic parameter which inherits from basicdata. i want to add many of this objects to a handler so that they all can be updated in a single method.
in java i have something like this:
public class BasicData
{
}
public abstract class Modul<T extends BasicData>
{
T value;
abstract void update(); // do something with the value
}
public class Handler
{
LinkedList<Modul<?>> modulCollection = new LinkedList<Data<?>>();
void add(Modul<?> m)
{
this.dataCollection.add(m);
}
void update(){
for(Modul<?> d : this.modulCollection){
d.update();
}
}
}
the list should contain various modul-objects, where the value field itself can have various types but they all inherit BasicData.
i searched a while, but i only found exotic solutions. is there no easy way to do the similar thing in c#? i dont want to rewrite my whole design.
at first i thought i could declare the list like this in c#:
LinkedList<Modul<BasicData>> collection;
void add(Modul<BasicData> m)
{
this.dataCollection.add(m);
}
and then add the various objects like this:
class DataImpl : Modul<int>
{
}
handler.add(new DataImpl());
but i found out that you cannot cast this Modul.
is there a solution to do something like that?
thanks in advance,
mick
C# does not have the ? wildcard mechanics as Java has - What is the equivalent of Java wildcards in C# generics, so there is no direct native solution for this problem.
POSSIBLE SOLUTIONS:
1. Use base non-generic class or interface for your Modul:
public abstract class ModulBase : BasicData
{
abstract void update(); // do something with the value
}
public abstract class Modul<T> : ModulBase ...
or
public interface IUpdateable
{
void Update();
}
public abstract class Modul<T> : BasicData, IUpdateable...
And use it like:
public class Handler
{
LinkedList<IUpdateable> modulCollection = new LinkedList<IUpdateable>();
void add<T>(Modul<T> m) // It is generic now
{
this.dataCollection.add(m);
}
void update(){
foreach (IUpdateable d in this.modulCollection){
d.update();
}
}
}
Your Handler.moduelCollection is no longer generic with such an approach, but in any case(even in Java) you would not have been able to access different generics in a simple manner without casting - and that is not the best way to handle different datatypes put into one collection.
You could try the same in C# like below:
public abstract class Module<T> where T : BasicData
{
}
I think I got a solution for you. It kinda uses what others and you said and combines it with something not mention here.
If you have class Foo
class Foo {
public virtual void Method1() {
//Do something
}
public void Method2() {
//Do something
}
//class code
}
Now, you have a class Bar which inherits from Foo
class Bar : Foo {
public override void Method1() {
//Do something
}
public new void Method2() {
//Do something
}
//class code
}
If you declare a variable of the class Bar and try to convert it to Foo, it is completely acceptable and you don't loose any data. However, the next time you want to use the extra properties, methods and variables, you will need to convert it back to Bar. Though, if common members are an override, they should behave as if they were called by a Bar variable, otherwise, if the object is cloned or cast backwards, the common members should behave as if they were called by an Foo instance.
For example:
Bar myBar = new Bar();
Foo myFoo = myBar; //Now myFoo and myBar refer to the same memory address
Foo myFoo2 = myBar.Clone() as Foo; //myFoo2 and myBar do not refer to the same memory address
//These should do exactly the same thing because Method1 is an override
myBar.Method1();
myFoo.Method1();
//These should not do exactly the same thing unless Method2 was not changed in Bar
myBar.Method2();
myFoo.Method2();
//These should do exactly the same thing because Method1 is an override
myBar.Method1();
myFoo2.Method1();
//These should not do exactly the same thing unless Method2 was not changed in Bar
myBar.Method2();
myFoo2.Method2();
Bar myBarConvertedBack = (Bar)myFoo; //No data lost
Now back to the question. Try this:
public abstract class Module<T> where T : BasicData {
protected T value;
public abstract void Update();
public virtual T Value {
get;
set;
}
}
public class Handler
{
LinkedList<Modul<BasicData>> modulCollection = new LinkedList<Data<BasicData>>();
pulic void Add(Modul<BasicData> m)
{
this.modulCollection.add(m);
}
public void Update() {
foreach (Modul<BasicData> d in this.modulCollection)
d.update();
}
}
Consider this class as possible derived class from Module:
public class Class1: Module<BasicData> {
public Class1(BasicData val) {
base.value = val;
}
public override void Update() {
//Do something here
}
public override BasicData Value {
get {
return base.value;
}
set {
base.value = value;
}
}
}
Also see more cases in stackoverflow in the Related or Linked to this question if it is clear. Furthermore, if I'm wrong somewhere correct me
I am trying to wrap my head around interfaces, and I was hoping they were the answer to my question.
I have made plugins and mods for different games, and sometimes classes have onUpdate or onTick or other methods that are overridable.
If I make an interface with a method, and I make other classes which implement the method, and I make instances of the classes, then how can I call that method from all the objects at once?
You'll be looking at the Observer pattern or something similar. The gist of it is this: somewhere you have to keep a list (ArrayList suffices) of type "your interface". Each time a new object is created, add it to this list. Afterwards you can perform a loop on the list and call the method on every object in it.
I'll edit in a moment with a code example.
public interface IMyInterface {
void DoSomething();
}
public class MyClass : IMyInterface {
public void DoSomething() {
Console.WriteLine("I'm inside MyClass");
}
}
public class AnotherClass : IMyInterface {
public void DoSomething() {
Console.WriteLine("I'm inside AnotherClass");
}
}
public class StartUp {
private ICollection<IMyInterface> _interfaces = new Collection<IMyInterface>();
private static void Main(string[] args) {
new StartUp();
}
public StartUp() {
AddToWatchlist(new AnotherClass());
AddToWatchlist(new MyClass());
AddToWatchlist(new MyClass());
AddToWatchlist(new AnotherClass());
Notify();
Console.ReadKey();
}
private void AddToWatchlist(IMyInterface obj) {
_interfaces.Add(obj);
}
private void Notify() {
foreach (var myInterface in _interfaces) {
myInterface.DoSomething();
}
}
}
Output:
I'm inside AnotherClass
I'm inside MyClass
I'm inside MyClass
I'm inside AnotherClass
Edit: I just realized you tagged it as Java. This is written in C#, but there is no real difference other than the use of ArrayList instead of Collection.
An interface defines a service contract. In simple terms, it defines what can you do with a class.
For example, let's use a simple interface called ICount. It defines a count method, so every class implementing it will have to provide an implementation.
public interface ICount {
public int count();
}
Any class implementing ICount, should override the method and give it a behaviour:
public class Counter1 implements ICount {
//Fields, Getters, Setters
#Overide
public int count() {
//I don't wanna count, so I return 4.
return 4;
}
}
On the other hand, Counter2 has a different oppinion of what should count do:
public class Counter2 implements ICount {
int counter; //Default initialization to 0
//Fields, Getters, Setters
#Overide
public int count() {
return ++count;
}
}
Now, you have two classes implementing the same interface, so, how do you treat them equally? Simple, by using the first common class/interface they share: ICount.
ICount count1 = new Counter1();
ICount count2 = new Counter2();
List<ICount> counterList = new ArrayList<ICount>();
counterList.add(count1);
counterList.add(count2);
Or, if you want to save some lines of code:
List<ICount> counterList = new ArrayList<ICount>();
counterList.add(new Counter1());
counterList.add(new Counter2());
Now, counterList contains two objects of different type but with the same interface in common(ICounter) in a list containing objects that implement that interface. You can iterave over them and invoke the method count. Counter1 will return 0 while Counter2 will return a result based on how many times did you invoke count:
for(ICount current : counterList)
System.out.println(current.count());
You can't call a method from all the objects that happen to implement a certain interface at once. You wouldn't want that anyways. You can, however, use polymorphism to refer to all these objects by the interface name. For example, with
interface A { }
class B implements A { }
class C implements A { }
You can write
A b = new B();
A c = new C();
Interfaces don't work that way. They act like some kind of mask that several classes can use. For instance:
public interface Data {
public void doSomething();
}
public class SomeDataStructure implements Data {
public void doSomething()
{
// do something
}
}
public static void main(String[] args) {
Data mydataobject = new SomeDataStructure();
}
This uses the Data 'mask' that several classes can use and have certain functionality, but you can use different classes to actually implement that very functionality.
The crux would be to have a list that stores every time a class that implements the interface is instantiated. This list would have to be available at a level different that the interface and the class that implements it. In other words, the class that orchestrates or controls would have the list.
An interface is a contract that leaves the implementation to the classes that implements the interface. Classes implement the interface abide by that contract and implement the methods and not override them.
Taking the interface to be
public interface Model {
public void onUpdate();
public void onClick();
}
public class plugin implements Model {
#Override
public void onUpdate() {
System.out.println("Pluging updating");
}
#Override
public void onClick() {
System.out.println("Pluging doing click action");
}
}
Your controller class would be the one to instantiate and control the action
public class Controller {
public static void orchestrate(){
List<Model> modelList = new ArrayList<Model>();
Model pluginOne = new plugin();
Model plugTwo = new plugin();
modelList.add(pluginOne);
modelList.add(plugTwo);
for(Model model:modelList){
model.onUpdate();
model.onClick();
}
}
}
You can have another implementation called pluginTwo, instantiate it, add it to the list and call the methods specified by the interface on it.
I am trying to do something I would not normally do, it is a bit odd, but I'd like to make it work. Essentially I have a factory that has to create objects by calling the constructor with different types of data (A and B take different types in the code below). I seem to have gotten my self stuck going down the generics route (I do need the code to be as compile time typesafe as possible). I am not opposed to writing the code differently (I'd like to keep the idea of the factory if possible, and I do not want to have to add in casts - so the "data" parameter cannot be an "Object").
Any thoughts on how to fix the code with generics or an alternative way of doing it that meets my requirements?
(Technically this is homework, but I am the instructor trying out something new... so it isn't really homework :-)
public class Main2
{
public static void main(String[] args)
{
X<?> x;
x = XFactory.makeX(0, "Hello");
x.foo();
x = XFactory.makeX(1, Integer.valueOf(42));
x.foo();
}
}
class XFactory
{
public static <T> X<T> makeX(final int i,
final T data)
{
final X<T> x;
if(i == 0)
{
// compiler error: cannot find symbol constructor A(T)
x = new A(data);
}
else
{
// compiler error: cannot find symbol constructor B(T)
x = new B(data);
}
return (x);
}
}
interface X<T>
{
void foo();
}
class A
implements X<String>
{
A(final String s)
{
}
public void foo()
{
System.out.println("A.foo");
}
}
class B
implements X<Integer>
{
B(final Integer i)
{
}
public void foo()
{
System.out.println("B.foo");
}
}
I don't see a way to make it work. I don't really think it should work either. When calling your makeX() function the calling code needs to know what integer parameter corresponds to what type of data to pass in. IOW, your abstraction is very leaky in the first place, and what you're really implementing is a rudimentary form of polymorphism, which you might as well use method overloading for, i.e.:
X makeX(String data) {
return new A(data);
}
X makeX(Integer data) {
return new B(data);
}
Of course it's a toy problem and all that. One way to make it work would be to make the client aware of implementation classes and add a Class<T> argument that you instantiate through reflection. But I suppose that would be kind of defeating the purpose.
I don't think what you're trying to do is possible without casting.
With casting, you have two options
if(i == 0)
{
x = new A((Integer)data);
}
else
{
x = new B((String)data);
}
}
or
class A
implements X<String>
{
A(final Object s)
{
}
}
...
class B
implements X<Integer>
{
B(final Object i)
{
}
}
Probably the closest thing you could get whilst retaining static type safety and having lazy construction is:
public static void main(String[] args) {
X<?> x;
x = aFactory("Hello").makeX();
x.foo();
x = bFactory(42).makeX();
x.foo();
}
private static XFactory aFactory(final String value) {
return new XFactory() { public X<?> makeX() {
return new A(value);
}};
}
public static XFactory bFactory(final Integer value) {
return new XFactory() { public X<?> makeX() {
return new B(value);
}};
}
interface XFactory() {
X<?> makeX();
}
So we create an instance of an abstract factory that creates the appropriate instance with the appropriate argument. As a factory, the product is only constructed on demand.
Clearly something had to give. What would you expect XFactory.makeX(1, "Hello") to do?
This is not possible without casting. As I have said elsewhere - generics don't remove the need for casting, but they mean that you can do all the casting in one place.
In the setup you describe, the factory method is exactly where all the under-the-hood work takes place. It's the spot where your code tells the compiler "I know you don't know what these types are, but I do, so relax.
It's entirely legit for your factory method to know that if i==1, then the data must be be of type Integer, and to check/enforce this with casting.