Related
I'm new to OOP and learning design patterns so I wrote some simple code to try out a Factory Method, and all seems well, except when I want to add another sub-type. Here's the code so far:
public interface Person {
public String getDescription();
}
public class Adult implements Person {
#Override
public String getDescription() {
return "I am an ADULT";
}
}
public class Child implements Person {
#Override
public String getDescription() {
return "I am a CHILD";
}
}
public class PersonFactory {
public Person create(int age) {
if (age < 18) return new Child();
return new Adult();
}
}
public class ClientA {
public static void main(String[] args) {
PersonFactory personFactory = new PersonFactory();
Person person;
person = personFactory.create(80);
System.out.println(person.getDescription());
}
}
If the requirement changes later to include a sub-class Pensioner for when the age is > 70, I would have to either:
Add the line if (age > 70) return new Pensioner(); to the create() method in the PersonFactory class, which surely breaks the Open-Closed Principle?
Or, as suggested in The Gang Of Four Design Patterns book, override the parameterized factory method to selectively extend the products a Creator produces. In this case I think that would mean writing a new class:
public class PersonFactoryWithPensioner extends PersonFactory {
#Override
public Person create(int age) {
if (age > 70) return new Pensioner();
return super.create(age);
}
}
This now means that either all the clients which call the PersonFactory would now have to be changed to use PersonFactoryWithPensioner instead, or I have to accept that new clients could call PersonFactoryWithPensioner whilst the old clients eg. ClientA would still only receive an Adult object when the age is > 70. It gets even worse if later on another sub-class eg. Infant is added. To ensure the new clients receive whichever object of Infant, Child, Adult or Pensioner is appropriate, a new class PersonFactoryWithInfant would have to extend PersonFactoryWithPensioner. This can't be right, seems more likely I have misunderstood what GoF suggest.
My question is: Is there a way to add a new sub-type that can be returned to old clients without changing them, and without breaking the OCP by changing the PersonFactory code to include the new sub-type?
Apologies if I have not posted this correctly, it is my first time posting a question here. I have looked through previous answers for similar problem but they don't seem to quite address this.
I think OCP doesn't stop from from modifying any method or class.
But, it proposes that if you need to do any modication, you should do it so that you don't have to modify that code again.
Given that you may need to modify PersonFactory later - you could create yet another Factory class to create objects of type PersonFactory. Although this seems like over-engineered solution.
Another possible solution would be that PersonFactory load this rules from some dynamic source, for example, save this rules in a file using JSON format.
And then create objects dynamically using reflection.
Something like this:
private static JSONObject RULES;
static {
RULES= JSON.parse(rulesEngine.load());
}
public class PersonFactory {
public Person create(int age) {
String personToCreate = RULES.get(age);
Constructor<?> ctor = Class.forName(personToCreate).getConstructor();
return (Person) ctor.newInstance();
}
}
The json rules would be something like this:
{
"1":"Child.class",
"2":"Child.class",
...,
"17":"Child.class",
"18":"Adult.class",
...,
"69":"Adult.class",
"70":"Pensioner.class"
}
This way you don't break OCP Principle.
The open-closed principle is good to keep in mind. It does not work nicely with factories, however. One option that sort-of-works is the following, which turns the factory into a registry:
PersonFactory pf = new PersonFactory();
// Java 8 lambdas are great!
pf.register((age) -> age < 18 ? new Child() : null );
pf.register((age) -> age >= 18 ? new Adult() : null );
System.out.println(pf.create(10).getDescription());
Similarly to #alayor's answer, the only way to avoid having to modify the logic of the factory, or having to replace the factory altogether and get everyone to use the new version... is for the factory to get its logic from elsewhere. #alayor gets it from a configuration file; I propose adding it to the factory as part of its initialization (could be done in the factory constructor too; changing it to, say, public PersonFactory(PersonCreator ... rules) ).
Full code:
interface PersonCreator {
Person create(int age);
}
class PersonFactory {
private List<PersonCreator> pcs = new ArrayList<>();
public void register(PersonCreator pc) {
pcs.add(pc);
}
public Person create(int age) {
for (PersonCreator pc : pcs) {
Person p = pc.create(age);
if (p != null) {
return p;
}
}
return null;
}
}
interface Person {
public String getDescription();
}
class Adult implements Person {
#Override
public String getDescription() {
return "I am an ADULT";
}
}
class Child implements Person {
#Override
public String getDescription() {
return "I am a CHILD";
}
}
public class Main {
public static void main(String[] args) {
PersonFactory pf = new PersonFactory();
// Java 8 lambdas are great!
pf.register((age) -> age < 18 ? new Child() : null );
pf.register((age) -> age >= 18 ? new Adult() : null );
System.out.println(pf.create(10).getDescription());
}
}
Rules are sometimes meant to be broken, so I say BREAK the Closed Principle to keep it clean and simple. The overhead of creating multiple Factory Classes for each type of person breaks the entire Factory Method purpose in my opinion. Breaking the Closed Principle allows you to have a single class to create any type of person.
public Person create(int age) {
if (age < 4) return new Infant();
if (age < 18) return new Child();
if (age < 70) return new Adult();
return new Pensioner();
}
All answers here, that suggests some kind of dynamic rules are in fact breaking open-close principle. This principle isn't about "don't change a piece of code that is already written" but "don't change a outcome of code already in use". That said, if a client expects that it only can get two results - Adult or Child then providing third possibility either by hardcoding it into function or by dynamic rulesets is breaking of open-close principle.
But returning to your question - I'll say it depends. Principles and patterns are nice, fun and all but in real day-to-day work one must always look at the big picture and decide if to apply certain rule or not. Treat them as hints, not something that's written in stone.
If your code is somewhat closed, that is you have control of every invocation of PersonFactory, then changes are just normal thing in the lifecycle of your software. I don't recall any real life project I've participated into, that hasn't changed any bit of code created previously. In fact we're doing it on the daily basis :)
Other thing is when your code is used by unknown number of third party clients (public API for example). Then you should be careful not to break something, but also presenting new logic in existing methods (as here when you add new concept of Person) is perfectly acceptable. If those would be breaking changes then consider adding new/upgraded version of changed code alongside old one (and possibly have a plan of deprecating old version sometime in the future as you really don't want to end up maintaining 10000 versions of your code ;)
Also remember about other OOP pieces that should help you avoid some problems. In your example Adult, Child and Pensioner all implements Person interface which is great. So any code that knows only Adult and Child implementations should not have problem with using Pensioner value as all of them are just implementations of Person and that code should treat Pensioner also as Person without even knowing you've introduced a new type.
The question is "do the client expect a Pensioner object to be created without code modification?". If yes, then you should break the "Closed" rule and update you factory code. If not, then you should create a new factory and the clients will use it.
I am now working on the AI section of my project. I am calling a method from my AI class which is intended to calculate where the Gladiator objects I have drawn need to actually end up. I passed to that method a List containing all my objects I want to place. A previous method from the AI class has determined where they want to be from each other, distance-wise and I have stored it as gladiator[0..1..2..etc].movementGoal.
Although the project is not real time, ie I will want to just "step" through it in the end, I do want simultaneous movement to occur. This means that my standard method of iterating through the list will not work as I need information about the other Gladiator's movement decisions in order to figure out any one Gladiator's actual movement as these decisions interact.
How can I access another specific gladiator's variables when I am outside the class and only have them in List form?
Edit:
I guess I could iterate through and test for a variable gladiatorNumber to be correct, then when it is pull that info? That would be pretty round-about but its all I can think of.
Edit2:
As requested, some code. My method in Ai class looks like this:
public void moveAI(List<Gladiator> gladiators) {
My gladiator is defined as such:
public class Gladiator {
Gladiator class is created as an array then added into a list in a separate main class. I don't really want to include more code than this, as there is a ton of it. Basically it boils down to how can I call gladiator[0] from AI class even though I created said object in the main class and only have them in list form in the AI class. Assume all variables in Gladiator are public. The error I am getting is cannot find symbol referring to gladiator[0...1...2...etc].
I think your problem boils down to wanting to pass the arrays of gladiators to another class. That should be fairly easy. If you in your main-class have these two defintions (note you only need one, I recommend the list as it is more versatile, arrays have fixed-length).
You want something like this:
public class Main {
// ....stuff
// This is the main class that keeps the list of gladiators
private List<Gladiator> gladiatorsList;
private Gladiator[] gladiatorsArray;
private MovementAI movementAI;
public Main() {
// You initialize gladiatorsList and gladiatorsArray as before
// gladiatorsList = ...
// gladiatorsArrray = ...
// Now you want to pass this list/array to another class (the AI), you
// can do this in the constructor of that class like so:
movementAI = new MovementAI(gladiatorsList);
}
// ...stuff as before
}
The AI
public class MovementAI {
private List<Gladiator> gladiators;
// Giving the class the list-reference, this list will be the same as the
// list in main, when main-list changes so does this one, they point to the
// same list-object, so the reference is only needed once.
public MovementAI(List<Gladiator> gladiatorsList) {
this.gladiators = gladiatorsList;
}
// The class already has a reference to the list from its constructor so it
// doesn't need the list again as a parameter
public void moveAI() {
}
// If you don't want to keep a reference to the list in this class but only
// use it in a method (I would not recommend this)
public MovementAI() {
}
// You need to pass it gladiatorsList everytime you call this method.
public void moveAI(List<Gladiator> gladiators) {
}
}
I see in your last comment that you have decided to let the AI decide to repaint if it meets a criteria, that is not recommended, you should keep responsibilities separate in your classes, less error-prone and better development. It is recommended to let the AI change the list of gladiators (move them, kill them etc) and the rendererclass simply paint every gladiator.
It also seems you want to have every gladiator be able to hold another gladiator as a target, it is better for them to hold the target as an Object, this way you don't have to search the entire list to find out which gladiator the gladiatornumber refers to and you don't have to think about ordering in the list. Something like this:
public class Gladiator {
// ..other stuff
private Gladiator target;
public Gladiator getTarget() {
return target;
}
public void setTarget(Gladiator target) {
this.target = target;
}
}
In English, a homograph pair is two words that have the same spelling but different meanings.
In software engineering, a pair of homographic methods is two methods with the same name but different requirements. Let's see a contrived example to make the question as clear as possible:
interface I1 {
/** return 1 */
int f()
}
interface I2 {
/** return 2*/
int f()
}
interface I12 extends I1, I2 {}
How can I implement I12? C# has a way to do this, but Java doesn't. So the only way around is a hack. How can it be done with reflection/bytecode tricks/etc most reliably (i.e it doesn't have to be a perfect solution, I just want the one that works the best)?
Note that some existing closed source massive piece of legacy code which I cannot legally reverse engineer requires a parameter of type I12 and delegates the I12 both to code that has I1 as a parameter, and code that has I2 as a parameter. So basically I need to make an instance of I12 that knows when it should act as I1 and when it should act as I2, which I believe can be done by looking at the bytecode at runtime of the immediate caller. We can assume that no reflection is used by the callers, because this is straightforward code. The problem is that the author of I12 didn't expect that Java merges f from both interfaces, so now I have to come up with the best hack around the problem. Nothing calls I12.f (obviously if the author wrote some code that actually calls I12.f, he would have noticed the problem before selling it).
Note that I'm actually looking for an answer to this question, not how to restructure the code that I can't change. I'm looking for the best heuristic possible or an exact solution if one exists. See Gray's answer for a valid example (I'm sure there are more robust solutions).
Here is a concrete example of how the problem of homographic methods within two interfaces can happen. And here is another concrete example:
I have the following 6 simple classes/interfaces. It resembles a business around a theater and the artists who perform in it. For simplicity and to be specific, let's assume they are all created by different people.
Set represents a set, as in set theory:
interface Set {
/** Complements this set,
i.e: all elements in the set are removed,
and all other elements in the universe are added. */
public void complement();
/** Remove an arbitrary element from the set */
public void remove();
public boolean empty();
}
HRDepartment uses Set to represent employees. It uses a sophisticated process to decode which employees to hire/fire:
import java.util.Random;
class HRDepartment {
private Random random = new Random();
private Set employees;
public HRDepartment(Set employees) {
this.employees = employees;
}
public void doHiringAndLayingoffProcess() {
if (random.nextBoolean())
employees.complement();
else
employees.remove();
if (employees.empty())
employees.complement();
}
}
The universe of a Set of employees would probably be the employees who have applied to the employer. So when complement is called on that set, all the existing employees are fired, and all the other ones that applied previously are hired.
Artist represents an artist, such as a musician or an actor. An artist has an ego. This ego can increase when others compliment him:
interface Artist {
/** Complements the artist. Increases ego. */
public void complement();
public int getEgo();
}
Theater makes an Artist perform, which possibly causes the Artist to be complemented. The theater's audience can judge the artist between performances. The higher the ego of the performer, the more likely the audience will like the Artist, but if the ego goes beyond a certain point, the artist will be viewed negatively by the audience:
import java.util.Random;
public class Theater {
private Artist artist;
private Random random = new Random();
public Theater(Artist artist) {
this.artist = artist;
}
public void perform() {
if (random.nextBoolean())
artist.complement();
}
public boolean judge() {
int ego = artist.getEgo();
if (ego > 10)
return false;
return (ego - random.nextInt(15) > 0);
}
}
ArtistSet is simply an Artist and a Set:
/** A set of associated artists, e.g: a band. */
interface ArtistSet extends Set, Artist {
}
TheaterManager runs the show. If the theater's audience judges the artist negatively, the theater talks to the HR department, which will in turn fire artists, hire new ones, etc:
class TheaterManager {
private Theater theater;
private HRDepartment hr;
public TheaterManager(ArtistSet artists) {
this.theater = new Theater(artists);
this.hr = new HRDepartment(artists);
}
public void runShow() {
theater.perform();
if (!theater.judge()) {
hr.doHiringAndLayingoffProcess();
}
}
}
The problem becomes clear once you try to implement an ArtistSet: both superinterfaces specify that complement should do something else, so you have to implement two complement methods with the same signature within the same class, somehow. Artist.complement is a homograph of Set.complement.
New idea, kinda messy...
public class MyArtistSet implements ArtistSet {
public void complement() {
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
// the last element in stackTraceElements is the least recent method invocation
// so we want the one near the top, probably index 1, but you might have to play
// with it to figure it out: could do something like this
boolean callCameFromHR = false;
boolean callCameFromTheatre = false;
for(int i = 0; i < 3; i++) {
if(stackTraceElements[i].getClassName().contains("Theatre")) {
callCameFromTheatre = true;
}
if(stackTraceElements[i].getClassName().contains("HRDepartment")) {
callCameFromHR = true;
}
}
if(callCameFromHR && callCameFromTheatre) {
// problem
}
else if(callCameFromHR) {
// respond one way
}
else if(callCameFromTheatre) {
// respond another way
}
else {
// it didn't come from either
}
}
}
Despite Gray Kemmey's valiant attempt, I would say the problem as you have stated it is not solvable. As a general rule given an ArtistSet you cannot know whether the code calling it was expecting an Artist or a Set.
Furthermore, even if you could, according to your comments on various other answers, you actually have a requirement to pass an ArtistSet to a vendor-supplied function, meaning that function has not given the compiler or humans any clue as to what it is expecting. You are completely out of luck for any sort of technically correct answer.
As practical programming matter for getting the job done, I would do the following (in this order):
File a bug report with whoever created an interface requiring ArtistSet and whoever generated the ArtistSet interface itself.
File a support request with the vendor supplying the function requiring an ArtistSet and ask them what they expect the behavior of complement() to be.
Implement the complement() function to throw an exception.
public class Sybil implements ArtistSet {
public void complement() {
throw new UnsupportedOperationException('What am I supposed to do');
}
...
}
Because seriously, you don't know what to do. What would be the correct thing to do when called like this (and how do you know for sure)?
class TalentAgent {
public void pr(ArtistSet artistsSet) {
artistSet.complement();
}
}
By throwing an exception you have a chance at getting a stack trace that gives you a clue as to which of the two behaviors the caller is expecting. With luck nobody calls that function, which is why the vendor got as far as shipping code with this problem. With less luck but still some, they handle the exception. If not even that, well, at least now you will have a stack trace you can review to decide what the caller was really expecting and possibly implement that (though I shudder to think of perpetuation a bug that way, I've explained how I would do it in this other answer).
BTW, for the rest of the implementation I would delegate everything to actual Artist and Set objects passed in via the constructor so this can be easily pulled apart later.
How to Solve For Your Specific Case
ArtistSet is simply an Artist and a Set:
/** A set of associated artists, e.g: a band. */
interface ArtistSet extends Set, Artist { }
From an OO perspective, that's not a useful declaration. An Artist is a type of noun, a "thing" that has defined properties and actions (methods).
A Set is an aggregate of things - a collection of unique elements. Instead, try:
ArtistSet is simply a Set of Artists.
/** A set of associated artists, e.g: a band. */
interface ArtistSet extends Set<Artist> { };
Then, for your particular case, the homonym methods are on interfaces that are never combined within the one type, so you have no clash and can program away...
Further, you don't need to declare ArtistSet because you aren't actually extending Set with any new declarations. You're just instantiating a type parameter, so you can replace all usage with Set<Artist>.
How to Solve For the More General Case
For this clash the method names don't even need to be homographic in the english language sense - they can be the same word with same english meaning, used in different contexts in java. Clash occurs if you have two interfaces that you wish to apply to a type but they contain the same declaration (e.g. method signature) with conflicting semantic/processing definitions.
Java does not allow you to implement the behaviour you request - you must have an alternative work-around. Java doesn't allow a class to provide multiple implementations for the same method signature from multiple different interfaces (implementing the same method multiple times with some form of qualification/alias/annotation to distinguish). See Java overriding two interfaces, clash of method names,
Java - Method name collision in interface implementation
Avoid use of Inheritence (extends or implements) and instead use Object Composition (see http://en.wikipedia.org/wiki/Composition_over_inheritance)
E.g. If you have the following
interface TV {
void switchOn();
void switchOff();
void changeChannel(int ChannelNumber);
}
interface Video {
void switchOn();
void switchOff();
void eject();
void play();
void stop();
}
Then if you have an object that is both of these things, you can combine the two in a new interface (optional) or type:
interface TVVideo {
TV getTv();
Video getVideo();
}
class TVVideoImpl implements TVVideo {
TV tv;
Video video;
public TVVideoImpl() {
tv = new SomeTVImpl(....);
video = new SomeVideoImpl(....);
}
TV getTv() { return tv };
Video getVideo() { return video };
}
How can I implement a class which has two superinterfaces having homographic methods?
In Java, a class which has two superinterfaces having homographic methods is considered to have only one implementation of this method. (See the Java Language Specification section 8.4.8). This allows classes to conveniently inherit from multiple interfaces that all implement the same other interface and only implement the function once. This also simplifies the language because this eliminates the need for syntax and method dispatching support for distinguishing between homographic methods based on which interface they came from.
So the correct way to implement a class which has two superinterfaces having homographic methods is to provide a single method that satisfies the contracts of both superinterfaces.
C# has a way to do this. How can it be done in Java? Is there no construct for this?
C# defines interfaces differently than Java does and therefore has capabilities that Java does not.
In Java, the language construct is defined to mean that all interfaces get the same single implementation of homographic methods. There is no Java language construct for creating alternate behaviors of multiply-inherited interface functions based on the compile time class of the object. This was a conscious choice made by the Java language designers.
If not, how can it be done with reflection/bytecode tricks/etc most reliably?
"It" cannot be done with reflection/bytecode tricks because the information needed to decide which interface's version of the homographic method to choose is not necessarily present in the Java source code. Given:
interface I1 {
// return ASCII character code of first character of String s
int f(String s); // f("Hello") returns 72
}
interface I2 {
// return number of characters in String s
int f(String s); // f("Hello") returns 5
}
interface I12 extends I1, I2 {}
public class C {
public static int f1(I1 i, String s) { return i.f(s); } // f1( i, "Hi") == 72
public static int f2(I2 i, String s) { return i.f(s); } // f2( i, "Hi") == 2
public static int f12(I12 i, String s) { return i.f(s);} // f12(i, "Hi") == ???
}
According to the Java language specification, a class implementing I12 must do so in such a way that C.f1(), C.f2(), and C.f12() return the exact same result when called with the same arguments. If C.f12(i, "Hello") sometimes returned 72 and sometimes returned 5 based on how C.f12() were called, that would be a serious bug in the program and a violation of the language specification.
Furthermore, if the author of class C expected some kind of consistent behavior out of f12(), there is no bytecode or other information in class C that indicates whether it should be the behavior of I1.f(s) or I2.f(s). If the author of C.f12() had in mind C.f("Hello") should return 5 or 72, there's no way to tell from looking at the code.
Fine, so I cannot in general provide different behaviors for homographic functions using bytecode tricks, but I really have a class like my example class TheaterManager. What should I do to implement ArtistSet.complement()?
The actual answer to the actual question you asked is to create your own substitute implementation of TheaterManager that does not require an ArtistSet. You do not need to change the library's implementation, you need to write your own.
The actual answer to the other example question you cite is basically "delegate I12.f() to I2.f()" because no function that receives an I12 object goes on to pass that object to a function expecting an I1 object.
Stack Overflow is only for questions and answers of general interest
One of the stated reasons to reject a question here is that "it is only relevant to an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet." Because we want to be helpful, the preferred way to handle such narrow questions is to revise the question to be more broadly applicable. For this question I have taken the approach of answering the broadly applicable version of the question rather than actually editing the question to remove what makes it unique to your situation.
In the real world of commercial programming any Java library that has a broken interface like I12 would not accumulate even dozens of commercial clients unless it could be used by implementing I12.f() in one of these ways:
delegate to I1.f()
delegate to I2.f()
do nothing
throw an exception
pick one of the above strategies on a per-call basis based on the values of some members of the I12 object
If thousands or even only a handful of companies are using this part of this library in Java then you can be assured they have used one of those solutions. If the library is not in use by even a handful of companies then the question is too narrow for Stack Overflow.
OK, TheaterManager was an oversimplification. In the real case it is too hard for me to replace that class and I don't like any of the practical solutions you've outlined. Can't I just fix this with fancy JVM tricks?
It depends on what you want to fix. If you want to fix your specific library by mapping all the calls to I12.f() and then parsing the the stack to determine the caller and choosing a behavior based on that. You can access the stack via Thread.currentThread().getStackTrace().
If you run across a caller you do not recognize you may have a hard time figuring out which version they want. For example you may be called from a generic (as was the actual case in the other specific example you gave), like:
public class TalentAgent<T extends Artist> {
public static void butterUp(List<T> people) {
for (T a: people) {
a.complement()
}
}
}
In Java, generics are implemented as erasures, meaning all type information is thrown away at compile time. There is no class or method signature difference between a TalentAgent<Artist> and a TalentAgent<Set> and the formal type of the people parameter is just List. There is nothing in the class interface or method signature of the caller to tell you what to do by looking at the stack.
So you would need to implement multiple strategies, one of which would be decompiling the code of the calling method looking for clues that the caller is expecting one class or another. It would have to be very sophisticated to cover all the ways this could happen, because among other things you have no way of knowing in advance what class it actually expecting, only that it is expecting a class that implements one of the interfaces.
There are mature and extremely sophisticated open source bytecode utilities, including one that automatically generates a proxy for a given class at runtime (written long before there was support for that in the Java language), so the fact that there isn't an open source utility for handling this case speaks volumes about the ratio of effort to usefulness in pursuing this approach.
Okay, after much research, I have another idea to fully accommodate the situation. Since you can't directly modify their code... you can force the modifications yourself.
DISCLAIMER: The example code below is very simplified. My intention is to show the general method of how this might be done, not to produce functioning source code to do it (since that's a project in itself).
The issue is that the methods are homographic. So to solve it, we can just rename the methods. Simple, right? We can use the Instrument package to achieve this. As you'll see in the linked documentation, it allows you to make an "agent" which can directly modify classes as they're loaded or re-modify them even if they've already been loaded.
Essentially, this requires you to make two classes:
An agent class which preprocesses and reloads classes; and,
A ClassFileTransformer implementation which specifies the changes you want to make.
The agent class must have either a premain() or agentmain() method defined, based on whether you want it to begin its processing as the JVM starts up or after it is already running. Examples of this are in the package documentation above. These methods give you access to an Instrumenation instance, which will allow you to register your ClassFileTransformer. So it might look something like this:
InterfaceFixAgent.java
public class InterfaceFixAgent {
public static void premain(String agentArgs, Instrumentation inst) {
//Register an ArtistTransformer
inst.addTransformer(new ArtistTransformer());
//In case the Artist interface or its subclasses
//have already been loaded by the JVM
try {
for(Class<?> clazz : inst.getAllLoadedClasses()) {
if(Artist.class.isAssignableFrom(clazz)) {
inst.retransformClasses(clazz);
}
}
}
catch(UnmodifiableClassException e) {
//TODO logging
e.printStackTrace();
}
}
}
ArtistTransformer.java
public class ArtistTransformer implements ClassFileTransformer {
private static final byte[] BYTES_TO_REPLACE = "complement".getBytes();
private static final byte[] BYTES_TO_INSERT = "compliment".getBytes();
#Override
public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
if(Artist.class.isAssignableFrom(classBeingRedefined)) {
//Loop through the classfileBuffer, find sequences of bytes
//which match BYTES_TO_REPLACE, replace with BYTES_TO_INSERT
}
else return classfileBuffer;
}
This is, of course, simplified. It will replace the word "complement" with "compliment" in any class which extends or implements Artist, so you will very likely need to further conditionalize it (for example, if Artist.class.isAssignableFrom(classBeingRedefined) && Set.class.isAssignableFrom(classBeingRedefined), you obviously don't want to replace every instance of "complement" with "compliment", as the "complement" for Set is perfectly legitimate).
So, now we've corrected the Artist interface and its implementations. The typo is gone, the methods have two different names, so there is no homography. This allows us to have two different implementations in our CommunityTheatre class now, each of which will properly implement/override the methods from the ArtistSet.
Unfortunately, we've now created another (possibly even bigger) issue. We've just broken all the previously-legitimate references to complement() from classes implementing Artist. To fix this, we will need to create another ClassFileTransformer which replaces these calls with our new method name.
This is somewhat more difficult, but not impossible. Essentially, the new ClassFileTransformer (let's say we call it the OldComplementTransformer) will have to perform the following steps:
Find the same string of bytes as before (the one representing the old method name, "complement");
Get the bytes before this which represent the object reference calling the method;
Convert those bytes into an Object;
Check to see if that Object is an Artist; and,
If so, replace those bytes with the new method name.
Once you've made this second transformer, you can modify the InterfaceFixAgent to accommodate it. (I also simplified the retransformClasses() call, since in the example above we perform the needed check within the transformer itself.)
InterfaceFixAgent.java (modified)
public class InterfaceFixAgent {
public static void premain(String agentArgs, Instrumentation inst) {
//Register our transformers
inst.addTransformer(new ArtistTransformer());
inst.addTransformer(new OldComplementTransformer());
//Retransform the classes that have already been loaded
try {
inst.retransformClasses(inst.getAllLoadedClasses());
}
catch(UnmodifiableClassException e) {
//TODO logging
e.printStackTrace();
}
}
}
And now... our program is good to go. It certainly wouldn't be easy to code, and it will be utter hell to QA and test. But it's certainly robust, and it solves the issue. (Technically, I suppose it avoids the issue by removing it, but... I'll take what I can get.)
Other ways we might have solved the problem:
The Unsafe API
A native method written in C
Both of these would allow you to directly manipulate bytes in memory. A solution could certainly be designed around these, but I believe it would be much more difficult and much less safe. So I went with the route above.
I think this solution could even be made more generic into an incredibly useful library for integrating code bases. Specify which interface and which method you need refactored in a variable, a command line argument, or a configuration file, and let her loose. The library that reconciles conflicting interfaces in Java at runtime. (Of course, I think it would still be better for everyone if they just fixed the bug in Java 8.)
Here's what I'd do to remove the ambiguity:
interface Artist {
void complement(); // [SIC] from OP, really "compliment"
int getEgo();
}
interface Set {
void complement(); // as in Set Theory
void remove();
boolean empty(); // [SIC] from OP, I prefer: isEmpty()
}
/**
* This class is to represent a Set of Artists (as a group) -OR-
* act like a single Artist (with some aggregate behavior). I
* choose to implement NEITHER interface so that a caller is
* forced to designate, for any given operation, which type's
* behavior is desired.
*/
class GroupOfArtists { // does NOT implement either
private final Set setBehavior = new Set() {
#Override public void remove() { /*...*/ }
#Override public boolean empty() { return true; /* TODO */ }
#Override public void complement() {
// implement Set-specific behavior
}
};
private final Artist artistBehavior = new Artist() {
#Override public int getEgo() { return Integer.MAX_VALUE; /* TODO */ }
#Override public void complement() {
// implement Artist-specific behavior
}
};
Set asSet() {
return setBehavior;
}
Artist asArtist() {
return artistBehavior;
}
}
If I were passing this object to the HR department, I'd actually give it the value returned from asSet() to hire/fire the entire group.
If I were passing this object to the Theater for a performance, I'd actually give it the value returned from asArtist() to be treated as talent.
This works as long as YOU are in control of talking to the different components directly...
But I realize that your problem is a single third-party vendor has created a component, TheaterManager, that expects one object for both of these functions and it won't know about the asSet and asArtist methods. The problem is not with the vendors that created Set and Artist, it is the vendor that combined them instead of using a Visitor pattern or just specifying an interface that would mirror the asSet and asArtist methods I made above. If you can convince your one vendor "C" to fix that interface, your world will be a lot happier.
Good luck!
Dog, I have a strong feeling you are leaving out some details that are crucial to the solution. This often happens on SO because
people need to leave out a lot of details to get the question to a reasonable size and scope,
people do not fully understand the problem and the solution (which is why they are asking for help) so they cannot be sure which details are important and which are not, and
the reason the person cannot solve the problem on their own is because they do not understand the importance of this detail, which is the same reason they left it out.
I've said in another answer what I would do about ArtistSet. But keeping the above in mind I will give you another solution to a slightly different problem. Lets say I had code from a bad vendor:
package com.bad;
public interface IAlpha {
public String getName();
// Sort Alphabetically by Name
public int compareTo(IAlpha other);
}
This is bad because you should declare a function returning a Comparator<IAlpha> to implement the sorting strategy, but whatever. Now I get code from a worse company:
package com.worse;
import com.bad.IAlpha;
// an Alpha ordered by name length
public interface ISybil extends IAlpha, Comparable<IAlpha> {}
This is worse, because it is totally wrong, in that it overrides behavior incompatibly. An ISybil orders itself by name length, but an IAlpha orders itself alphabetically, except an ISybil is an IAlpha. They were mislead by the anti-pattern of IAlpha when they could and should have done something like:
public interface ISybil extends IAlpha {
public Comparator<IAlpha> getLengthComparator();
}
However, this situation is still much better than ArtistSet because here the expected behavior is documented. There is no confusion about what ISybil.compareTo() should do. So I would create classes as follows. A Sybil class that implements compareTo() as com.worse expects and delegates everything else:
package com.hack;
import com.bad.IAlpha;
import com.worse.ISybil;
public class Sybil implements ISybil {
private final Alpha delegate;
public Sybil(Alpha delegate) { this.delegate = delegate; }
public Alpha getAlpha() { return delegate; }
public String getName() { return delegate.getName(); }
public int compareTo(IAlpha other) {
return delegate.getName().length() - other.getName().length();
}
}
and an Alpha class that works exactly like com.bad said it should:
package com.hack;
import com.bad.IAlpha;
public class Alpha implements IAlpha {
private String name;
private final Sybil sybil;
public Alpha(String name) {
this.name = name;
this.sybil = new Sybil(this);
}
// Sort Alphabetically
public int compareTo(IAlpha other) {
return name.compareTo(other.getName());
}
public String getName() { return name; }
public Sybil getSybil() { return sybil; }
}
Note that I included type conversion methods: Alpha.getSybil() and Sybil.getAlpha(). This is so I could create my own wrappers around any com.worse vendor's methods that take or return Sybils so I can avoid polluting my code or any other vendor's code with com.worse's breakage. So if com.worse had:
public ISybil breakage(ISybil broken);
I could write a function
public Alpha safeDelegateBreakage(Alpha alpha) {
return breakage(alpha.getSybil).getAlpha();
}
and be done with it, except I would still complain vociferously to com.worse and politely to com.bad.
I am practicing inheritance.
I have two similar classes that I'd like to assimilate into one array, so I thought to use the Object class as a superclass since everything is a sublcass of Object.
So, for example I put T class and CT class into an array called all like so:
Object all[] = new Object[6];
all[0] = T1;
all[1] = CT2;
all[2] =T3;
all[3] = CT1;
all[4] = T2;
all[5] = CT3;
I skipped the declarations as thats not my problem.
My real issue becomes when I wish to call a function within the array utilizing a loop:
for (int i = 0; i < 6; i++) {
all[i].beingShot(randomNum, randomNum, AK47.getAccuracy());
}
The classes involved with T and CT respectively both have the beingShot method, which is public.
Eclipse advises casting them as a quick fix. I'm wondering if there is any logical alternative other than creating my own Object class that holds the beingShot method, or adding this to the class of Object, although I feel either of these choices would cause more problems in the long run.
Thanks!
If both classes implement the same method(s), you should consider creating an interface.
Interfaces are very powerful and easy to use.
You could call your interface Shootable.
You can create an array of different objects that implement Shootable and treat them all the same.
// Define a VERY simple interface with one method.
interface Shootable {
public void beingShot();
}
// Any class that implements this interface can be treated interchangeably
class Revolver implements Shootable {
public void beingShot() {
System.out.println("Revolver: firing 1 round");
}
class MachineGun implements Shootable {
public void beingShot() {
System.out.println("Machine Gun: firing 50 rounds");
}
}
class HockeyPuck implements Shootable {
public void beingShot() {
System.out.println("Hockey Puck: 80 MPH slapshot");
}
}
class RayBourquePuck implements Shootable {
public void beingShot() {
System.out.println("Hockey Puck: 110 MPH slapshot");
}
}
class OunceOfWhiskey implements Shootable {
public void beingShot() {
System.out.println("Whiskey Shot: 1 oz down the hatch...");
}
}
// You can declare an array of objects that implement Shootable
Shootable[] shooters = new Shootable[4];
// You can store any Shootable object in your array:
shooters[0] = new MachineGun();
shooters[1] = new Revolver();
shooters[2] = new HockeyPuck();
shooters[3] = new OunceOfWhiskey();
// A Shootable object can reference any item from the array
Shootable anyShootableItem;
// The same object can to refer to a MachineGun OR a HockeyPuck
anyShootableItem = shooters[0];
anyShootableItem.beingShot();
anyShootableItem = shooters[2];
anyShootableItem.beingShot();
// You can call beingShot on any item from the array without casting
shooters[0].beingShot();
shooters[1].beingShot();
// Let's shoot each object for fun:
for (Shootable s : shooters) {
s.beingShot();
}
Here's a great related question and answer.
Object doesn't have the method beingShot. If all of the objects in array are of the same class, then your array should be of that same class. Otherwise they all should have same interface implemented or extend the same class. I can't imagine why would you want explicitly extend Object here, it doesn't add any functionality whatsoever.
You need to typecast your object references to appropriate class to call their method..
For each reference you fetch from your array, you need to check using instanceof operator, of which is the instance referred to by your object reference.. Accordingly you can typecast the reference to that class..
But Typecasting is an ugly thing.. You should avoid it as far as possible.. If you have to choose which method to invoke based on exact sub class, you should probably go with an Interface.. It is the best way you can achieve what you want here...
And I think you have got enough information about how to implement it..
You cant do it...since Java does not support extension method. (C# does)
READ THE LINK BELOW:
Java equivalent to C# extension methods
Let's say I have an object of the class Car, with like 30 variables ranging from top speed to color. I want to make a MyCar object (class MyCar extends Car) that is basically the same thing except it stores some more information.
It is not possible for me to create MyCar objects right away (since out of thousands of Car objects only a few will become MyCar objects), unless I leave the additional fields blank, but that doesn't seem too professional. And neither does creating a constructor which takes 30 arguments, or setting 30 arguments through method calls.
So, is there any way to easily inherit all the variables from a superclass object?
PS: My program is not about cars, but I figured it would be an easier example.
EDIT
Thanks for the replies. They are all helpful for my program, but not for this particular problem. Builders don't seem beneficial because these cars of mine don't have default values for their variables. Every time a car is made, all the variables are filled out (which is needed to construct a sort of "fact-sheet").
Envelopes are an interesting design, but still require me to copy all the variables in the subclass constructor. I was hoping there would be a way to circumvent this. Templates would also require me to copy all the variables one by one.
In my program the subclass acts as a sort of "wrapper class" in a search engine. The subclasses are the same as the normal cars, but they have a "ranking score". My program is designed to display regular cars, and by extending those I can easily display the subclasses and order them by score at the same time.
I have to create new objects anyway, because multiple searches can be performed on the same list of cars. So editing variables in the original cars was not an option.
Maybe there is a better solution to this problem, but for now I guess I'll have to pass the superclass object into the constructor and copy all the variables there.
Thanks for the help!
PS: I'm just thinking, perhaps I could throw all the variables into a HashMap. That way I could access them by using .get(varname), and I would only have to pass one HashMap variable into the subclass. Downside is I would have to cast a lot, since the vars are a mixture of Strings, ints, doubles etc. What do you think, is it acceptable coding style?
Effective Java 2nd Edition, Item 2: Consider a builder when faced with many constructor parameters
And neither does creating a
constructor which takes 30 arguments,
or setting 30 arguments through method
calls.
If you are facing a constructor with too many parameters then you might want to have a look at: The Builder Pattern.
The idea is to set only the field you want/know into the builder, without bothering with the optional ones, or ones that you'd want to use default values, then calling build() to construct the actual object. See the Java examples in that article.
Once you have setup that pattern, you can construct Cars this way (notice the clean structure):
Car car = new Car.Builder(required_param1, required_param2)
.color(RED) // optional params
.topSpeed(300)
.zeroToHundred(2)
.build();
You can add a constructor that gets a Car object and copy the values from the Car to the new MyCar.
It is not possible for me to create MyCar objects right away (since out of thousands of Car objects only a few will become MyCar objects),
So, you'll have lots of objects of Car type, a few of which you'd like to, at runtime, "promote" to SpecialCar type?
Do SpecialCars have exactly the same interface as Cars?
You might want to read up on Coplien's Envelope-Letter Pattern, it's a way of "changing" object type at runtime. The object doesn't really change type, of course; instead, a different "Letter" goes into the existing "Envelope". The Envelope is the handle that other code references, but method calls on the Envelope are delegated to the Letter:
class CarEnvelope { // an envelope
Car c ; // the letter
CarEnvelope( Car c ) { this.c = c ; }
int someMethod() {
return c.someMethod(); // delegate
}
void promoteToSpecialType() {
if( ! c.isSpecialCar() ) {
c = new SpecialCar( c ) ;
}
}
class Car {
Car() {}
int someMethod() { do Car stuff }
boolean isSpecial() { return false; }
}
class SpecialCar extends Car {
SpecialCar( Car c ) { /*copy c's attributes...*/ }
int someMethod() { do SpecialCar stuff}
boolean isSpecial() { return true; }
}
CarEnvelope c = new CarEnvelope( new Car() ) ;
// do stuff with c
c.someMethod(); // indirectly calls Car.someMethod();
// promote
c.promoteToSpecialType();
c.someMethod(); // indirectly calls SpecialCar.someMethod
OP here.
I understand that this looks like laziness. But I already have it working by manually copying 30 variables in the constructor. Not that big of a task, I know.
The thing is, I have been taught to code with style. When I see mindless code blocks that look like copypasta my instincts tell me that there is probably a better way. So my desire to learn and strive for perfection has driven me here.
But if there really is no other way than to copy the variables (or override all the get&set methods) then I don't have to look any further.
Needless to say, all the replies in this topic have given me new insights. Thanks guys.
I have a feeling that what you are looking for is the notion of a template; e.g.
public class Car {
private final int attr1;
private final int attr2;
...
public Car() {
super();
}
/* copy constructor */
public Car(Car template) {
this.attr1 = template.attr1;
this.attr2 = template.attr2;
...
}
/* setters and getters */
}
Then ...
Car myTemplate = new Car();
myTemplate.setAttr1(3);
myTemplate.setAttr2(11);
...
Car car1 = new Car(myTemplate);
car1.setAttr1(4);
Car car2 = new Car(myTemplate);
car1.setAttr1(5);
I don't get it. What's wrong with a regular inheritance?
class Car {
private int attributeOne;
.....
private boolean attrbuteThirty;
public void methodOne(){...}
...
public void methodThirty(){...}
}
And then just subclass it:
class SubCar extends Car {
private int extraAttribute;
}
All the 30+ attributes and methods are already inherited, that's what the extends is all about.
If what you need is to create a new object based on the data of an existing one, but you're resisting to code it! ( ¬¬ ) , then you may just create a small script to create the code for you. It's very easy. You copy/paste the generated code and you're done.
If you don't want to do it, because you don't want to duplicate the data, you may override interesting methods, and delegate the code to the original, that's what the Decorator design pattern is all about:
class SubCar extends Car {
private Car wrapped;
private String extraAttribute;
public SubCar( Car original, String newAttributeOne ) {
wrapped = original;
this.extraAttribute = newAttributeOne;
}
public void someMethod() {
wrapped.someMethod();
}
public String getName() { return wrapped.getName(); }
... and so on
// new method
public String extraAttribute() { return extraAttribute; }
}
That way you won't duplicate the data, but just decorate it.
We can create an interface ICar that has all the getters and setters for all the 30 columns.
Car can implement ICar and can contain all the 30 fields with their corresponding getters and setters.
MyCar can also implement ICar and can use composition. It exposes Car's methods as delegate methods (which can automatically be generated in an IDE like eclipse)
public interface ICar {
// getter and setter methods
}
public Car implements ICar {
private String color;
// getters and setters for each of the fields
}
public MyCar implements ICar {
private Car car;
public MyCar(Car car){
this.car = car;
}
public String getColor() {
return car.getColor();
}
}
All consumers could then use the ICar interface for their manipulation. Will that work?