Class instantiating objects of arbitrary classes. What pattern to use? - java

I'm new to Java and I hope Java experts will not vote down my question just because it may seem rather primitive to them. So, this is something I want to achive in semi-pseudo code:
class Big {
? magic_field;
? magic_method (int _idx){
if (_idx == 1){
magic_field = new Object_1();
}
else if (_idx == 2){
magic_field = new Object_2();
}
...
else if (_idx == N){
magic_field = new Object_N();
}
return magic_field;
}
}
I've already tried to ask this question, but in the context of a real world class, real fields and procedures, but did not get an answer to my question. Practically all answers reused the idea of generics and started with something like
class Big <T extends Something>
But I want stress it heavily thousands of times - Object_1, Object_2, ..., Object_N may be drastically different classes that do not relate to each other - they are not subclasses of some parent class, they are not subclasses of each other. They are absolutely different and in fact are black boxes for each other. So, the idea of T extends Something does not work, because there is nothing to extend. Though, I've provided a semi-pseudo example, in an answer I wish to see a real class - and for simplicity let it be generalized on two arbitrary classes. Thanks!

Magic field simple should be an Object if there is no relation between the types (everything is an Object!)
Something like this:
class Big {
private Object magic_field;
public Object magic_method (int _idx){
if (_idx == 1){
magic_field = new Object_1();
}
else if (_idx == 2){
magic_field = new Object_2();
}
...
else if (_idx == N){
magic_field = new Object_N();
}
return magic_field;
}
}
class Object_1 {
//...
}
class Object_2 {
//...
}
class Object_N {
//...
}

Java is a strong, statically typed programming language. What you ask is first of all is not vary natural in the java context if you do not want to use generics. Maybe you can port it to a dynamically typed language like Ruby, Racket, Python vs or you can extend a type system for the Java language.
So you can write it like that as Johan Graham suggested.
Object magicField;
magicField = new ClassA();
magicField = new ClassB();
Then you should store also the type that you have bidden to your magicField variable because you need reflection to extract data from it.

Related

JAVA AND OR and IF

basically what needs to happen is that it needs to check what the type of Champion is, and compare it to challenges to see if it can actually do that challenge, its quite hard to explain...
a wizard can fight "magic" and "mystery"
a warrior can fight "fight" and "mystery"
a dragon can fight "fight" and "mystery(only if the dragon talks)"
what I have come up with is this...
public boolean canFight(String nme, int id)
{
Challenge chal = getChallengeObj(id);
Champion champ = getChampionObj(nme.toLowerCase());
if(champ.getType().equals("wizard") && (chal.getTypeAsString().equals("magic") || chal.getTypeAsString().equals("fight"))) {
return true;
} else if(champ.getType().equals("warrior") && (chal.getTypeAsString().equals("fight") || chal.getTypeAsString().equals("mystery"))) {
return true;
} else if((champ.getType().equals("dragon") || champ.getType().equals("dragon") && champ.isMystery()) && (chal.getTypeAsString().equals("fight") || chal.getTypeAsString().equals("magic"))) {
return true;
} else {
return false;
}
}
I thank anyone who has a go at helping me, I am open to any response, even complaints on how complicated the code is!!
(It is checking everything toLowerCase() btw, just in case this isnt clear in the code, as it is in the methods that are called in different classes.
THANKS!!
EDIT
The problem is is that it keeps returning false, and I am a second year university student, so if you could give examples of what you mean by your answers, that would be greatly appreciated :)
Thanks again
The best way to get different behaviour from different types in Java is using polymorphism - basically, put a virtual method into your Champion type with different implementations in Wizard, Warrior, Dragon etc subtypes
A chain of if-else's based on the type of an object is a bit of an anti-pattern in Java - crying out to be refactored into a single call to a virtual method.
Why not use a 2D array to map FightCompatilibity between Challenge and Champ. Model each Champ and Challenge as enum. Maybe, take a look at Visitor Pattern. It might be useful.
This is exactly something, which should be done by class hiearchy. Like if you know, someone is Wizard, you should already known what he can attack or not, therefore you should move responsibility into that Wizard class instead of testing it externally.
I did an example with 4 classes :
In this enum are listed all attack types
public enum AttackTypes {
Magic, Meele, Ranged;
}
This is abstract class, it only helps you define behaviour that is same for all classes. I supposed that every class has some subset of "attack types" (or something similar). In my example, I just suppose, that each class can fight only against some types of attack. In constructor, I get all the attack I can fight and then I can chack it with this canAttack.
public abstract class Champion {
private List<AttackTypes> attackTo;
public Champion(AttackTypes... attack) {
this.attackTo = new ArrayList<>();
this.attackTo.addAll(Arrays.asList(attack));
}
public boolean canAttack(AttackTypes attackType){
for (AttackTypes attack : attackTo){
if (attack == attackType){
return true;
}
}
return false;
}
}
This is simple Warrior class, in my example, it can fight only Magic and Meele :
public class Warrior extends Champion{
public Warrior(){
super(AttackTypes.Magic, AttackTypes.Meele);
}
}
And similar to Warrior, here is Wizard :
public class Wizard extends Champion{
public Wizard(){
super(AttackTypes.Ranged, AttackTypes.Magic);
}
}
This approach is important, because it is extremely easy to add new class (like Ranger for example). You just add him and thats all, you dont have to anything in your already finished code.
Then you can use it as following :
Champion wizard = new Wizard();
Champion warrior = new Warrior();
AttackTypes attackType = AttackTypes.Ranged;
System.out.println("can wizard attack? : " + wizard.canAttack(attackType));
System.out.println("can warrior attack? : " + warrior.canAttack(attackType));
This having this output :
can wizard attack? : true
can warrior attack? : false
A much more flexible approach would be to use a pair of enums. Something like this would be a good start. I haven't exactly implemented your logic because there is a flaw in it:
enum Champion {
Wizard(EnumSet.of(Challenge.Fight, Challenge.Magic)),
Warrior(EnumSet.of(Challenge.Fight, Challenge.Mystery)),
Dragon(EnumSet.of(Challenge.Fight, Challenge.Magic)) {
#Override
public boolean canFight(Champion enemy, Challenge attack) {
// For demonstration.
return susceptible.contains(attack) && enemy == Champion.Dragon;
}
};
protected final Set<Challenge> susceptible;
Champion(Set<Challenge> susceptible) {
this.susceptible = susceptible;
}
public boolean canFight(Champion enemy, Challenge attack) {
return susceptible.contains(attack);
}
}
enum Challenge {
Magic,
Fight,
Mystery;
}
You flaw is in (champ.getType().equals("dragon") || champ.getType().equals("dragon") && champ.isMystery()) which doesn't make sense.

How to refactor a method to make it easier to test

Below is a method that I'm having a hard time figuring out how to test using JUnit.
This method is difficult to test because it depends on the results of other methods (e.g. getClosestDcoumentCode).
Based on my reading of JUnit, this suggests I should refactor the method. But how? And if refactoring is not necessary, how do you test a method that depends on other methods?
Thank you,
Elliott
private static String findPrincipal(List<DocumentKey> documentkeys_) {
Hashtable<String, Integer> codecounts = new Hashtable<String, Integer>();
for (DocumentKey document : documentkeys_) {
int x = 0;
String closestCode = getClosestDocumentCode(document.candidates);
if (closestCode == null) continue;
int thecount = 0;
if (codecounts.containsKey(closestCode))
thecount = codecounts.get(closestCode);
if (document.hasKey)
thecount += 2;
else
thecount++;
codecounts.put(closestCode, new Integer(thecount));
x++;
}
String closestCode = getClosestCode(codecounts);
return closestCode;
}
Well, first of all, I wonder if the method really needs to be static, and what that class is doing. It looks like it might be a GOD class, or at the very least it's violating the single responsibility principle. What does getClosestCode do? If it was a class, you could inject it with a stub in your tests into the test class.
EasyMock will let you mock the method response, but I'm not sure how you mock static methods.
In general, you probably need to
Extract long functions into classes
Make functionality non-static
Maintain the single responsibility principal
It sounds to me like getClosestCode and getClosestDocumentCode belong to a different set of responsibilities than the findPrincipal method. So you'll want to begin by separating these into two different classes. Create an interface for each class to implement. The class that implements the findPrincipal method can then rely on the other interface as a constructor argument, like this:
public class PrincipalFinderImpl implements PrincipalFinder
{
private CodeFinder codeFinder;
public PrincipalFinderImpl(CodeFinder codeFinder) {
this.codeFinder = codeFinder;
}
public String findPrincipal(List<DocumentKey> documentkeys_) {
Hashtable<String, Integer> codecounts = new Hashtable<String, Integer>();
for (DocumentKey document : documentkeys_) {
int x = 0;
String closestCode = codeFinder.getClosestDocumentCode(document.candidates);
if (closestCode == null) continue;
int thecount = 0;
if (codecounts.containsKey(closestCode))
thecount = codecounts.get(closestCode);
if (document.hasKey)
thecount += 2;
else
thecount++;
codecounts.put(closestCode, new Integer(thecount));
x++;
}
String closestCode = codeFinder.getClosestCode(codecounts);
return closestCode;
}
}
Now it should be easy to create another class the implements the CodeFinder interface, either manually or using a Mocking framework. You can then control the results of each call to getClosestCode and getClosestDocumentCode, and ensure that each of these methods gets called with exactly the arguments you expect it to be called with.
I don't read the method deeply. But if a private method needs to test, it indicates something wrong with your design. At least Kent Beck thinks so.
There is a chapter on stub calls on JUnit Second Edition, i recommend you have a look at that if you think your existing codes are not written to test-driven development standards.

Struggle against habits formed by Java when migrating to Scala

What are the most common mistakes that Java developers make when migrating to Scala?
By mistakes I mean writing a code that does not conform to Scala spirit, for example using loops when map-like functions are more appropriate, excessive use of exceptions etc.
EDIT: one more is using own getters/setters instead of methods kindly generated by Scala
It's quite simple: Java programmer will tend to write imperative style code, whereas a more Scala-like approach would involve a functional style.
That is what Bill Venners illustrated back in December 2008 in his post "How Scala Changed My Programming Style".
That is why there is a collection of articles about "Scala for Java Refugees".
That is how some of the SO questions about Scala are formulated: "help rewriting in functional style".
One obvious one is to not take advantage of the nested scoping that scala allows, plus the delaying of side-effects (or realising that everything in scala is an expression):
public InputStream foo(int i) {
final String s = String.valueOf(i);
boolean b = s.length() > 3;
File dir;
if (b) {
dir = new File("C:/tmp");
} else {
dir = new File("/tmp");
}
if (!dir.exists()) dir.mkdirs();
return new FileInputStream(new File(dir, "hello.txt"));
}
Could be converted as:
def foo(i : Int) : InputStream = {
val s = i.toString
val b = s.length > 3
val dir =
if (b) {
new File("C:/tmp")
} else {
new File("/tmp")
}
if (!dir.exists) dir.mkdirs()
new FileInputStream(new File(dir, "hello.txt"))
}
But this can be improved upon a lot. It could be:
def foo(i : Int) = {
def dir = {
def ensuring(d : File) = { if (!d.exists) require(d.mkdirs); d }
def b = {
def s = i.toString
s.length > 3
}
ensuring(new File(if (b) "C:/tmp" else "/tmp"));
}
new FileInputStream(dir, "hello.txt")
}
The latter example does not "export" any variable beyond the scope which it is needed. In fact, it does not declare any variables at all. This means it is easier to refactor later. Of course, this approach does lead to hugely bloated class files!
A couple of my favourites:
It took me a while to realise how truly useful Option is. A common mistake carried from Java is to use null to represent a field/variable that sometimes does not have a value. Recognise that you can use 'map' and 'foreach' on Option to write safer code.
Learn how to use 'map', 'foreach', 'dropWhile', 'foldLeft', ... and other handy methods on Scala collections to save writing the kind of loop constructions you see everywhere in Java, which I now perceive as verbose, clumsy, and harder to read.
A common mistake is to go wild and overuse a feature not present in Java once you "grokked" it. E.g. newbies tend to overuse pattern matching(*), explicit recursion, implicit conversions, (pseudo-) operator overloading and so on. Another mistake is to misuse features that look superficially similar in Java (but ain't), like for-comprehensions or even if (which works more like Java's ternary operator ?:).
(*) There is a great cheat sheet for pattern matching on Option: http://blog.tmorris.net/scalaoption-cheat-sheet/
I haven't adopted lazy vals and streams so far.
In the beginning, a common error (which the compiler finds) is to forget the semicolon in a for:
for (a <- al;
b <- bl
if (a < b)) // ...
and where to place the yield:
for (a <- al) yield {
val x = foo (a).map (b).filter (c)
if (x.cond ()) 9 else 14
}
instead of
for (a <- al) {
val x = foo (a).map (b).filter (c)
if (x.cond ()) yield 9 else yield 14 // why don't ya yield!
}
and forgetting the equals sign for a method:
def yoyo (aka : Aka) : Zirp { // ups!
aka.floskel ("foo")
}
Using if statements. You can usually refactor the code to use if-expressions or by using filter.
Using too many vars instead of vals.
Instead of loops, like others have said, use the list comprehension functions like map, filter, foldLeft, etc. If there isn't one available that you need (look carefully there should be something you can use), use tail recursion.
Instead of setters, I keep the spirit of functional programming and have my objects immutable. So instead I do something like this where I return a new object:
class MyClass(val x: Int) {
def setX(newx: Int) = new MyClass(newx)
}
I try to work with lists as much as possible. Also, to generate lists, instead of using a loop, use the for/yield expressions.
Using Arrays.
This is basic stuff and easily spotted and fixed, but will slow you down initially when it bites your ass.
Scala has an Array object, while in Java this is a built in artifact. This means that initialising and accessing elements of the array in Scala are actually method calls:
//Java
//Initialise
String [] javaArr = {"a", "b"};
//Access
String blah1 = javaArr[1]; //blah1 contains "b"
//Scala
//Initialise
val scalaArr = Array("c", "d") //Note this is a method call against the Array Singleton
//Access
val blah2 = scalaArr(1) //blah2 contains "d"

Java: For loop and If algorithm

I've this question from an assignment to create a Store which rent out books, using a Store.java and Book.java. I've finished this assignment, but I'm curious for better algorithm to a specific part.
--
Book.java
public class Book {
private String name;
Book(String name)
this.name = name;
public String getName()
return name;
}
Store.java
Inside main();
Book bookObj[] = new Book[3]; //Create 3 Array of Object.
bookObj[0] = new Book("Game Over");
bookObj[1] = new Book("Shrek");
bookObj[2] = new Book("Ghost");
Scanner console = new Scanner(System.in)
input = console.nextLine();
Assuming, input = Devil.
Now, I need to do a simple search to check whether the specific book exist.
Example:
for(int i = 0; i < bookObj.length; i++) {
if(bookObj[i].getName().equals(input))
System.out.println("Book Found!");
}
Apparently, this is a for loop that cycles through the array of object and checks whether such Book exist. Now, the problem arise when I want to give an output that the Book was not found.
Example:
for(int i = 0; i < bookObj.length; i++) {
if(bookObj[i].getName().equals(input))
System.out.println("Book Found!");
else
System.out.println("Book not Found!");
}
The problem with the above code is that Book not Found would be printed thrice. My goal is to avoid such problem. I do have solutions to this, but I'm still in search for a better one to use that utilizes getName(), which in my opinion still has room to improve.
Usually, in structural programming, I would do the following,
for(int i = 0; i < bookObj.length; i++) {
if(bookObj[i].getName().equals(input))
System.out.println("Book Found!");
else if(i == bookObj.length - 1)
System.out.println("Book not Found!");
}
This is useful to tell whether it's the end of the loop, and the search has ended, but there was no successful result from the search.
How should I think of it in Object Oriented way?
All in all, my question is,
Is there a better way to write the above code rather than checking that it's the end of the line?
Is there a better way to utilize getName() method or to use other methods?
You should loop through the array and use an index / boolean flag to store whether or not the book is found. Then print the message in the end, based on the index / flag value.
int foundAtIndex = -1;
for(int i = 0; i < bookObj.length; i++) {
if(bookObj[i].getName().equals(input)) {
foundAtIndex = i; // store the actual index for later use
break; // no need to search further
}
}
if(foundAtIndex >= 0)
System.out.println("Book Found!");
else
System.out.println("Book not Found!");
Alternatively (unless your assignment specifically requires using an array) you should prefer a Set, which can do the search for you with a single call to contains().
How should I think of it in Object Oriented way?
When looking at a single method, there is not much difference between procedural and OO style. The differences start to appear at a higher level, when trying to organize a bunch of conceptually related data and methods that operate on these.
The OO paradigm is to tie the methods to the data they operate on, and encapsulate both into coherent objects and classes. These classes are preferably representations of important domain concepts. So for your book store, you may want to put all book related code into your Book class. However, the above search method (and the collection of books it operates on) is not related to any particular book instance, so you have different choices:
put both the collection of books and the search method into Store (probably as regular members), or
put them into Book as static members.
The first choice is more natural, so I normally would prefer that. However, under specific circumstances the second option might be preferable. In (OO) design, there are hardly ever clean "yes/no" answers - rather tradeoffs between different options, each having their own strengths and weaknesses.
You could introduce state and remember whether you have found the book or not.
If you're not using Java 1.4 or earlier, you could also use the foreach loop syntax:
boolean bookFound = false;
for(Book currentBook : bookObj) {
if(currentBook.getName().equals(input))
//TODO: see above
}
Also, I would suggest looking into the Collections library, and replace your array with a list or set:
Set<Book> books = new HashSet<Book>();
books.put(new Book("Game Over"));
books.put(new Book("Shrek"));
books.put(new Book("Ghost"));
And, while were at it, you could also think about when two books are equal and override equals() and hashCode() accordingly. If equal() would be changed to check the title, you could simply use books.contains(new Book(input)); and have the libraries do the work for you.
To solve the problem in a better way you must understand that the power of Java comes not from the language itself but from the Java Framework.
You should learn the usage of the Java Collection classes (never work with arrays anymore). Then you will be able to solve the search with just one line of code:
ArrayList<Book> listOfBooks;
// init your list here
listOfBooks.contains(new Book(input));
To make this work, you must also learn how to correctly implement the equals() method of your Book class.
Happy learning!
Here is a working solution :
import java.util.Scanner;
public class Store {
private static class Book {
private String name;
Book(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public static void main(String[] args) {
String input;
Book[] bookObj = new Book[3];
bookObj[0] = new Book("Game Over");
bookObj[1] = new Book("Shrek");
bookObj[2] = new Book("Ghost");
Scanner console = new Scanner(System.in);
input = console.nextLine();
boolean found = false;
int i = 0;
while(!found && i < bookObj.length) {
if(bookObj[i].getName().equals(input)) {
System.out.println("Book Found at position : " + i);
found = true;
} else {
i++;
}
}
if(!found) {
System.out.println("Book not Found!");
}
// Here i contains the indice of the element found in the array.
}
}
You've gotten some pretty good advice thus far. You asked if there was a more Object Oriented way of thinking about the problem so I thought I'd try and shed some light on it. As Peter already mentioned at this level of the design it's a single method implementation so the approach is going to be fairly similar as say a procedural approach. What's the advantage? In a word reuse. If you needed to find a book by name in lots of places then moving the code to it's own class will help.
So what you have is a single Book instance to encapsulate behavior around a single book, but you want to have behavior about multiple books, or a collection of books. You can keep the data (array of books), and the method that account on them separate as you outlined in your program. However, if we wanted to collect a place for doing behavior on a collection of books we can define a new class. Let's call it Library, and we might do something like the following:
public class Library {
private Book[] books;
private bookCount = 0;
public Library( int numberOfTotalBooks ) {
books = new Book[numberOfTotalBooks];
}
public boolean addBook( Book book ) {
if( bookCount < book.length ) {
books[bookCount++] = book;
return true;
}
return false;
}
public Book findByTitle( String title ) {
for( int i = 0; i < bookCount; i++ ) {
if( books[i].getTitle().equals( title ) ) {
return books[i];
}
}
// didn't find one
return null;
}
}
So a couple of things to note about doing things this way. One is that when we work with a Library we don't know there is an Array back there. We could use an array, a Set, a List, or a database (most common). The point being the code that calls these functions just works with the interface of Library (not a literal Java interface, but the method signature of Library). Also this is a higher level interface. We don't worry about iterating over the books, doing for loops, if statements, etc. We just call a method saying "Hey find this book title in the Library". How that's done we don't care. This is the basic tenant of Object Orientation called encapsulation, and it's deceptively powerful. It's really about how we delegate responsibility in our program, and give the details of a job to individual class or classes. If Library had only public members (i.e. books and bookCount), or getter/setters then the client wouldn't be getting any advantages because the client would still have to do all the heavy lifting. The trick to OO is figuring out what can be delegated out of an object, without creating problems. This takes practice, and experience.
The second thing here is we've separated the presentation from the act of finding a book. The method you wrote assumed the next step which was to print "Hey we found it." However, Library object simply returns the Book to you when it finds it, or null if it didn't. That makes it possible to print to the console, display in a GUI, or serialize it to a JSON stream in a server. The act of finding a book is separate from the visualization. This is another important aspect of programming in general, but some what related to object orientation and encapsulation. This is typically called separation of concerns. The console application has concerns about supporting the UI, and printing the console. While the Library just manages cataloging and managing the book collection. How those details are performed neither cares.
In the end Library is a reusable class. We can use it in a console application, desktop, web, or middleware server. More importantly is we can also reuse the calls to findByTitle or addBooks from multiple locations within a single program. Also by putting the methods with the data we create a barrier to where that function can be used. You can't do it anywhere in your program. You have to have a reference to Library. If you don't have reference to a Library instance then you shouldn't be calling it. This can be troublesome to new developers because they lack the experience to properly organize their programs to not get into trouble with this (then they start doing value objects, creating statics, singletons, etc and things turn into a big ball of mud). It's a double edged sword.
One more thing I'd like to point out is say we wanted to model two Libraries. We have a Library uptown and downtown, and we want to allow people to check out books from either Library. With OO that's really easy to represent:
Library uptown = new Library( 50 );
Library downtown = new Library( 100 );
Now we can check out books from one or the other. And I didn't use statics (i.e. global variables) so reusing that logic is really easy. These are the basics of OO so they are really deep topics. Strange how I can write so much on very simple topics. Anyway I hope this helped you understand your program a little deeper, and see how you can use OO to help you.
chubbsondubs came closest to giving a correct answer to this question
What he missed is that his algorithm is incorrect because it contains two tests, when only one is needed. The correct code requires only 3 statements and is as follows:
public boolean zLibaryContains( String title ) {
books[bookCount] = title;
int xBook = 0;
while( true )
if( books[xBook].getTitle().equals( title ) )
return xBook != bookCount;
else xBook++;
}
Noticeably smaller and faster than all other solutions. Simplify, simplify, simplify.
Object-oriented code is a crutch to support poor designs that would otherwise be too complex to understand. The goal is write code that is so easy to understand and maintain that OO is unnecessary and would make the program worse. When your program can be improved by adding OO, it means you are doing something wrong to begin with.

Best method to create a new instance based on precondition

Hi my question is this. Suppose you have an interface that defines how a converter would be implemented. This interface could have a method loadDocument() and another convert(). Now suppose we want to have multiple converters, ConvertHTML2DOC, ConvertXML2HTML e.t.c you get the idea.
Suppose you get the two formats you need to convert in 2 strings (doesn't matter HOW you get them). Now you need to create an instance of your converter and convert the documents.
My question is which is better: to actually create an elaborate if statement or to load the classes through reflection with the Class class? to demonstrate I wrote a little example of what I mean. In my example I have 2 classes P1 and P2 that share an interface. I also create 50000 of them to show of the speed differences. As it turns out the normal invocation is slightly faster, but I think that in a complex example such as the one i mentioned in the beginning, the benefits of creating the classes through the Class method is more convenient and more maintainable. What are your thoughts?
import java.util.*;
public class Test {
public static void main(String[] args) {
try {
Random r = new Random();
Date test1start = new Date();
for (int i = 0; i<= 50000; i++){
Printable p = (Printable)Class.forName("P"+(r.nextInt(2)+1)).newInstance();
System.out.println(p.getString());
}
Date test1stop = new Date();
Date test2start = new Date();
for (int i = 0; i<= 50000; i++){
Printable p;
if (r.nextInt(2) == 0 ) {
p = new P1();
} else {
p = new P2();
}
System.out.println(p.getString());
}
Date test2stop = new Date();
System.out.println("Test with 'Class' invocation took "+(test1stop.getTime()-test1start.getTime())+" milliseconds.");
System.out.println("Test with 'normal' invocation took "+(test2stop.getTime()-test2start.getTime())+" milliseconds.");
} catch (Exception e) {
}
}
}
interface Printable {
public String getString();
}
class P1 implements Printable {
public String getString(){
return "1";
}
}
class P2 implements Printable {
public String getString(){
return "2";
}
}
You should definitely follow the advice from Javier - a registry of factories is the right way to go for this problem. I've implemented it that way many times in the past, be for format translation or some other extensible "predicate" based factory solution (eg, automatic GUI generation based on reflection information).
I would however suggest one addition to the design - the introduction of a common domain model (CDM) that is targeted by all translators. Say that you have formats A, B and C an that you need to support transformation between each - you get all the permutations:
A -> B
A -> C
B -> A
B -> C
C -> A
C -> B
As the number of format grows, you get an explosion of transformations! A better idea is to separate each transformation into two parts - lets call it an importer and an exporter. The importer converts a format to the common domain model (CDM) while an export converts the from the CDM to some format.
As an example, we decompose the conversion from A to B into the following:
A --> CDM (this is an import)
CDM --> B (this is an export)
Now when you want to add a new format you need only write an importer and an exporter but you get translation to/from all other formats! Talk about extensible! It also allows for formats for which yo can read but not write and vice versa.
So, the solution would be to have a registry of importer factories and a registry of exporter factories.
definitely use a factory method; but instead of a "big if", or name-mangling, use a "class registration" method. for this, the factory class maintains a table where each concrete class registers it's condition (in your case it's the source and target names) and the constructor (it's a 'condition->constructor' dictionary). the factory itself simply constructs the dictionary key and fetches the constructor it needs.
one big advantage is that each concrete class encapsulates the condition it solves, and you can add more without changing the factory method.
Try something like this, compile time safety, with the one-lineness of the Class.forName.
public class PrintableFactory
{
public enum Type
{
HTML,
DOC,
}
public static Printable getPrintable(final Type from, final Type to)
{
final Printable printable;
if(from == HTML && to == DOC)
{
printable = new HtmlToDoc();
}
else if(from == DOC && to == HTML)
{
printable = new DocToHTML();
}
else
{
// you decide if you want runtime or compile time exception handling
// could also return numm but I don't like that myself.
throw new ImpossibleConversionException(from, to);
}
return (printable);
}
}

Categories