I have this scenario. I started working with a system that 'process' documents. The problem is, it seems to be the typical scenario where it started small, and went getting bigger and bigger constructing it one chunk at a time and now it needs to be refactored.
Each document type has an identifier (docID), and all of them share the same underlying result structure.
There is a huge master class that does all the job BUT inside this class there are several methods (almost one for each site) with its own logic. They all do almost the same with slight changes (i.e. formatting a string before setting it to a field in the result structure or doing some calculation and then setting the field in the result structure).
For example:
private Result processDocGeneric(Result result){
result.setField1("value1");
result.setField2("value2");
result.setField3("value3");
return result;
}
private Result processDoc1(Result result){
result.setField1("VALUE1");
return result;
}
private Result processDoc2(Result result){
result.setField2("V-A-L-U-E-2");
return result;
}
private void processDocs(){
Result result = new Result();
result = processDocGeneric(result);
if(docID == 1){
result = processDoc1(result);
}
else if(docID == 2){
result = processDoc2(result);
}
...
}
Ok, so I'm planning to refactor this and I'm considering some design patterns I know but I don't want the feel that I'm killing a roach with a bazooka.
Command pattern is maybe the first that comes to my mind, also Strategy pattern. My major concern with those is that I will have to create a class for every document type that has its own implementation of the processDoc method (There are around 15 at the moment). I mean, if that's the way to go, that would be it but if there's a simpler way of doing it that I don't know, it would be better (since the change is in a single method).
The other thing that I could do is moving all those method to a 'methods' class, and also move the if-else block to a single method with a docID parameter (process(int docID) and then call it from the main class. But that's just splitting the huge class. It would be "cleaner" but not optimal.
What would be the best approach to clean and split this huge class and make it scalable (since there would be new document types to be added in the future)?.
You can use factory or abstract factory design patterns maybe, In this patterns you can get your needed objects without having to specify the exact class of the object that will be created.
I propose a solution based on the Visitable / Visitor Pattern. this solution requires very little change to the Result class, while opening the door to new visiting objects, making it an easily extensible framework. I'm making heavy use of Java8's default interface method.
The Visitor / Visitable Interfaces:
public interface DocVisitor<T extends VisitableDoc> {
default void visit(T document){
switch(document.getDocId()){
case 1:
processDoc1(document);
break;
case 2:
processDoc2(document);
break;
// ... other cases...
default:
processDocGeneric(document);
break;
}
}
void processDocGeneric(VisitableDoc document);
void processDoc1(VisitableDoc document);
void processDoc2(VisitableDoc document);
}
public interface VisitableDoc {
int getDocId();
default void visit(DocVisitor visitor){
visitor.visit(this);
}
}
Slight modification of the Result class:
public class Result implements VisitableDoc { // New interface declared
int getDocId(){
return docId; // This might already exist
}
// Rest is unchanged, the default implementation will suffice
}
A Visitor Implementation:
public class DocProcessor implements DocVisitor<Result> {
#Override
private Result processDocGeneric(Result result){
result.setField1("value1");
result.setField2("value2");
result.setField3("value3");
return result;
}
#Override
private Result processDoc1(Result result){
result.setField1("VALUE1");
return result;
}
#Override
private Result processDoc2(Result result){
result.setField2("V-A-L-U-E-2");
return result;
}
}
Usage:
public static final main(String[] args){
List<Result> results = // Obtain results somehow
DocProcessor processor = new DocProcessor();
for(Result result: results){
processor.visit(result);
}
}
[How to] split this huge class and make it scalable (since there would be new document types to be added in the future
What I've done is merely to split Document data on Result class / Document Processing on DocProcessor class. If you have other processing that differ from type to type, and which can be extracted to an external class (no need for private field handling, private methods calling etc.), this framework os completely applicable.
If not, you should REALLY consider refactoring it to use polymophism! Make each Document type its own object. Use a strong abstract class to link them all, and if you have many methods that are shared accross several but not all types, then make sub-types accordingly - or use default methods! Java8 FTW
For this situation is applicable builder pattern.
/**
*
* Hero, the class with many parameters.
*
*/
public final class Hero {
private final Profession profession;
private final String name;
private final HairType hairType;
private final HairColor hairColor;
private final Armor armor;
private final Weapon weapon;
private Hero(Builder builder) {
this.profession = builder.profession;
this.name = builder.name;
this.hairColor = builder.hairColor;
this.hairType = builder.hairType;
this.weapon = builder.weapon;
this.armor = builder.armor;
}
public Profession getProfession() {
return profession;
}
public String getName() {
return name;
}
public HairType getHairType() {
return hairType;
}
public HairColor getHairColor() {
return hairColor;
}
public Armor getArmor() {
return armor;
}
public Weapon getWeapon() {
return weapon;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("This is a ")
.append(profession)
.append(" named ")
.append(name);
if (hairColor != null || hairType != null) {
sb.append(" with ");
if (hairColor != null) {
sb.append(hairColor).append(' ');
}
if (hairType != null) {
sb.append(hairType).append(' ');
}
sb.append(hairType != HairType.BALD ? "hair" : "head");
}
if (armor != null) {
sb.append(" wearing ").append(armor);
}
if (weapon != null) {
sb.append(" and wielding a ").append(weapon);
}
sb.append('.');
return sb.toString();
}
/**
*
* The builder class.
*
*/
public static class Builder {
private final Profession profession;
private final String name;
private HairType hairType;
private HairColor hairColor;
private Armor armor;
private Weapon weapon;
/**
* Constructor
*/
public Builder(Profession profession, String name) {
if (profession == null || name == null) {
throw new IllegalArgumentException("profession and name can not be null");
}
this.profession = profession;
this.name = name;
}
public Builder withHairType(HairType hairType) {
this.hairType = hairType;
return this;
}
public Builder withHairColor(HairColor hairColor) {
this.hairColor = hairColor;
return this;
}
public Builder withArmor(Armor armor) {
this.armor = armor;
return this;
}
public Builder withWeapon(Weapon weapon) {
this.weapon = weapon;
return this;
}
public Hero build() {
return new Hero(this);
}
}
}
Related
Here is some part of the practice.
I created an abstract parent class called Equipment, which has four child classes as shown as ConcreteMixer. Then the exercise asked me to create a class named Job, in which its constructor is as shown in the figure. I can’t understand the meaning of the list parameter, but I still created a class according to its requirements, and set it in It is instantiated in the main function.
This is the result of instantiation. I don’t know what the result of this parameter instantiation has to do with Equipment and its subclasses
public abstract class Equipment {
String requirement;
public Equipment(String requirements){
this.requirement=requirements;
}
public String getRequirement() {
return requirement;
}
}
public class ConcreteMixer extends Equipment{
public ConcreteMixer(String requirement){
super(requirement);
}
public String toString(){
return requirement;
}
#Override
public boolean equals(Object obj) {
if(obj instanceof ConcreteMixer) {
ConcreteMixer that = (ConcreteMixer) obj;
return this.requirement.equals(that.requirement);
} return false;
}
}
public Job(Address location, String description,List<Equipment> requiredEquipment, Date plannedDate) {
this.location = location;
this.description = description;
this.requiredEquipment = requiredEquipment;
this.plannedDate = plannedDate;
}
public static void main(String[] args) {
Job s= new Job(new Address("Star street",16, "da","London"),"mixer",new
ArrayList<Equipment>(),new Date(12,5,21));
System.out.println(s);
}
}
and this is the result for the main method
location:Address isLondonStar street16da
description:mixer
requiredEquipment:[]
plannedDate:day:12
month:5
year:21
As shown, your image shows nothing about using (or defining) your Equipment subclasses
But the point of the parameter is that the job can use multiple of any Equipment type
List<Equipment> e = new ArrayList<>();
e.add(new ConcreteMixer("concrete"));
Job j = new Job(..., e,...);
Below is my Builder pattern class which generates an Employee Object.
public class Employee {
// required parameters
private String HDD;
private String RAM;
// optional parameters
private boolean isGraphicsCardEnabled;
private boolean isBluetoothEnabled;
public String getHDD() {
return HDD;
}
public String getRAM() {
return RAM;
}
public boolean isGraphicsCardEnabled() {
return isGraphicsCardEnabled;
}
public boolean isBluetoothEnabled() {
return isBluetoothEnabled;
}
private Employee(EmployeeBuilder builder) {
this.HDD=builder.HDD;
this.RAM=builder.RAM;
this.isGraphicsCardEnabled=builder.isGraphicsCardEnabled;
this.isBluetoothEnabled=builder.isBluetoothEnabled;
}
public static class EmployeeBuilder {
private String HDD;
private String RAM;
// optional parameters
private boolean isGraphicsCardEnabled;
private boolean isBluetoothEnabled;
public EmployeeBuilder(String hdd, String ram){
this.HDD = hdd;
this.RAM = ram;
}
public EmployeeBuilder isGraphicsCardEnabled(Boolean isGraphicsCardEnabled){
this.isGraphicsCardEnabled = isGraphicsCardEnabled;
return this;
}
public EmployeeBuilder isBluetoothEnabled(boolean isBluetoothEnabled){
this.isBluetoothEnabled = isBluetoothEnabled;
return this;
}
public Employee build(){
return new Employee(this);
}
}
public static void main(String args[]){
Employee emp = new Employee.EmployeeBuilder("500", "64").
isGraphicsCardEnabled(true).
isGraphicsCardEnabled(true).build();
System.out.println(emp.HDD);
System.out.println(emp.getHDD());
}
}
A builder whose parameters have been set makes a fine Abstract Factory [Gamma95, p. 87]. In other words, a client can pass such a builder to a method to enable the method to create one or more objects for the client. To enable this usage, you need a type to represent the builder. If you are using release 1.5 or a later release, a single generic type (Item 26) suffices for all builders, no matter what type of object they’re building.
Can anyone add some light on the above paragraph with an working example. I am not able to understand the above para which is taken from Effective Java - Joshua Bloch.
I'm trying to mimic the following abstract class, designed to enable only one lazy initialization, without using logic statements. I'm ignoring the synchronization elements necessary for thread safety for simplicity's sake.
abstract class Thunk<T>
{
private boolean initiated = false;
private T value;
public T get()
{
if(!initiated) // not using (value == null)
{
value = compute();
initiated = true;
}
return value;
}
abstract protected T compute();
}
Can an instance of the following abstract class be hacked by a child to initialize the same variable more than once?
abstract class Thunk<T>
{
private T value;
private Computer<T> computer;
public Thunk()
{
computer = new Computer<T>(this);
}
public T get()
{
value = computer.getValue();
return value;
}
abstract protected T compute();
private class Computer<T>
{
private static final String TAG = "Computer";
private Thunk<T> thunk;
private T value;
private Computer<T> computer;
public Computer(Thunk<T> thunk)
{
Log.d(TAG, "constructed");
this.thunk = thunk;
computer = this;
}
public T getValue()
{
Log.d(TAG + ".getValue()", "");
value = computer.computeValue();
return value;
}
protected T computeValue()
{
Log.d(TAG + ".computeValue()", "");
value = thunk.compute();
computer = new DumbComputer<T>(thunk, value);
return value;
}
//this is for maximal encapsulation
private class DumbComputer<T> extends Computer<T>
{
private static final String TAG = "DumbComputer";
private T value;
public DumbComputer(Thunk<T> thunk, T value)
{
super(thunk);
Log.d(TAG + ".contructed()", "booki");
this.value = value;
}
//overriding so that value will be calculated only once.
#Override
protected T computeValue()
{
Log.d(TAG + ".computeValue()", "");
return value;
}
}
}
}
Yes, by overriding the get method.
To fix that you can make the get into a final method. That will prevent overriding and give you singleton-like behaviour.
Note that the code you have written is not thread safe.
You could achieve thread safety by making the method synchronized (don't worry about performance until you know you gave a problem and that the method is the hotspot, because slow correct code is better than fast incorrect code, and the JVM is very good at optimising locks. If you find a specific lock for this class to be excessively hot, you can use a number of tricks to speed it up... but don't worry about that just yet)
Also worth pointing out the resource holder inner class pattern for lazy init (not applicable to your use case as this class need. It be used for only singletons) can be used if you wan the best lazy init of singletons.
update (responding to comment as comments don't support formatting)
Do this:
abstract class Thunk<T>
{
private boolean initiated = false;
private T value;
public synchronized final T get()
{
if(!initiated) // not using (value == null)
{
value = compute();
initiated = true;
}
return value;
}
abstract protected T compute();
}
That is the simplest code that can possibly work. Don't even dream of trying to "improve" that code. It can be improved, but the improvements will differ depending on how the class is being used, and the complexity of the improvement will hide what your code is trying to do. Start with the simplest thing that can work, and go from there.
Keep It Simple Stupid
And don't solve problems you don't have yet
The pattern
public final void f() {
...
X x = ...;
g(x);
...
}
abstract protected void g(X x);
is quite usefull in contractual programming:
to impose a behaviour (body of f), and
to provide a local context (x).
A behaviour often is realized by holding a state (like your initiated).
So yes, it is fine for lazy evaluation. Though lazy evaluation can be achieved on field level, for instance by the seldom seen jewel Future<>.
Your second example does not work as (probably) intended, as you create a new DumbComputer each time you call Thunk.get. You can achieve your goal as follows (but I do not think it's good design, and I really do not see where the advantage compared to an easier solution shuld be):
abstract class Thunk<T> {
T value;
Computer<T> computer;
protected abstract T doCompute ();
private interface Computer<T> {
Computer getComputer ();
T compute ();
}
public Thunk<T> () {
// initialize computer with a calculating one
computer = new Computer<T> () {
Computer getComputer () {
// return a dumb computer
return new Computer<T> () {
Computer getComputer () { return this; }
T compute () { return value; }
}
}
T compute () { value = doCompute (); return value; }
};
}
public T getValue () {
T v = computer.compute (); computer = computer.getComputer (); return v;
}
}
I am currently working with XML files, and am searching to have a better way to avoid try/catch blocks in a nice way.
Here is the thing. Let's say I have an XML file.
<A>
<BB>37</BB>
<CC>
<DDD>1</DDD>
</CC>
</A>
In fact, I turn this into an object, which means that I can do
myXml.getA() and so on.
In my code, I search a lot for given elements in this object, which means that I have a lot of lines like
int ddd = myXml.getA().getCC().getDDD();
The thing is that some elements may not be there, and for example another XML element can be like that only :
<A'>
<BB'>37</BB'>
</A'>
So if I try to get ddd, getCC() raises a NullPointerException.
In the end, I end up coding it like that :
int ddd;
try{
ddd = myXml.getA().getCC().getDDD();
}
catch (NullPointerException e){
ddd = 0;
}
This works but the code becomes really ugly.
I am searching for a solution to have something like
int ddd = setInt(myXml.getA().getCC().getDDD(), 0);
0 being the default in case the method raises an exception.
Is there a nice way to do that ?
Up to now, I couldn't find a solution that do not raise errors.
Thx for your help !
EDIT: Just not to get XML related answers.
I showed the xml part for everybody to understand the problem.
In my code, I don't have access to the XML, but only the object that represents it.
To make it short, what I'd really love is some kind of isNull method to test my getters.
This is sort of an annoyance of working with jaxb. in my company, we do enough work with jaxb that it was worth writing an xjc plugin which generated "safe" versions of every getter that were guaranteed to return non-null values for any non-trivial value (immutable instances in the case that a sub-object did not really exist).
Here's an example of what our generated model entities look like:
public class ExampleUser implements Serializable {
private final static long serialVersionUID = 20090127L;
#XmlAttribute
protected String name;
#XmlAttribute
protected String email;
public final static ExampleUser EMPTY_INSTANCE = new ExampleUser() {
private static final long serialVersionUID = 0L;
#Override
public void setName(java.lang.String value) { throw new UnsupportedOperationException(); }
#Override
public void setEmail(java.lang.String value) { throw new UnsupportedOperationException(); }
};
public String getName() {
return name;
}
public void setName(String value) {
this.name = value;
}
public String getEmail() {
return email;
}
public void setEmail(String value) {
this.email = value;
}
}
public class ExampleAccount implements Serializable {
private final static long serialVersionUID = 20090127L;
protected ExampleUser user;
#XmlElement(name = "alias")
protected List<String> aliases;
#XmlAttribute
protected String id;
#XmlAttribute
protected String name;
public final static ExampleAccount EMPTY_INSTANCE = new ExampleAccount() {
private static final long serialVersionUID = 0L;
#Override
public void setUser(com.boomi.platform.api.ExampleUser value) { throw new UnsupportedOperationException(); }
#Override
public List<String> getAliases() { return java.util.Collections.emptyList(); }
#Override
public void setId(java.lang.String value) { throw new UnsupportedOperationException(); }
#Override
public void setName(java.lang.String value) { throw new UnsupportedOperationException(); }
};
public ExampleUser getUser() {
return user;
}
public void setUser(ExampleUser value) {
this.user = value;
}
public List<String> getAliases() {
if (aliases == null) {
aliases = new ArrayList<String>();
}
return this.aliases;
}
public String getId() {
return id;
}
public void setId(String value) {
this.id = value;
}
public String getName() {
return name;
}
public void setName(String value) {
this.name = value;
}
public ExampleUser safeGetUser() {
return (getUser() != null) ? getUser() : ExampleUser.EMPTY_INSTANCE;
}
}
So you could write this code without fear of NPE:
userEmail = account.safeGetUser().getEmail();
You can look at the Null objec pattern.
For example :
public class A {
private C c;
public C getC() {
if (c == null) {
c = new C(0); // the "null object"
}
return c;
}
}
public class C {
private int d;
public C(int d) {
this.d = d;
}
public int getD() {
return d;
}
}
But personnaly, i have a bad feeling with this code :
int ddd = myXml.getA().getCC().getDDD();
It is a strong violation of the law of Demeter. The class invoker have a too large knowledge of A, C and D. This code will be clearly difficult to adapt and maintain.
The two general approaches to this sort of problem are the null object pattern that other answers have already covered, and type safe nulls such as Scala's Option.
http://www.scala-lang.org/api/current/scala/Option.html
There are a few Java versions of Option knocking around.
http://functionaljava.googlecode.com/svn/artifacts/2.20/javadoc/fj/data/Option.html
http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/base/Optional.html
Type safe nulls can be particular useful when combined with the flatmap.
Use Apache common-beanutils to create your set method. It will use reflection and then you have only a single place to catch the errors.
It would look something like this (haven't coded it so excuse syntax errors).
int getInt(Object root, String beanPattern, int defaultValue)
{
try
{
return PropertyUtils.getNestedProperty(root, beanPattern);
}
catch (Exception e)
{
return 0;
}
}
This would be called like so.
int ddd = getInt(myXml, "A.CC.DDD", 0);
Can't you just write a function which is general enough to be called for each value, and is returning the value or 0.
Something like
myGetSomething(FOO){
try {getFOO} catch ...
}
Then your Code itself looks nice, but the function has basically a try-catch for each call.
Use Xpath query instead of get methods. It will give you an empty list if it cannot find the element path.
List ddds = myXml.query("/AA/BB/CC/DDD");
if (!ddds.empty()) {}
The correct syntax depends on the XML library you use.
Write part of the code in Groovy or Xtend; both support the ?. syntax which returns null of the left hand side of the expression evaluates to null. They also get rid of the useless get so you can write:
myXml.a?.cc?.ddd
The syntax of Xtend is worse when compared to Groovy but it compiles to plain Java, so you just need to add a single JAR with some helper classes to your code to use the result.
Suppose you create a class names Person using the builder pattern, and suppose the Builder class contains methods body(), head(), arms() and of course build() and you consider methods head() and build() obligatory for the user of this class.
We would like to somehow mark these methods obligatory, if possible using annotations. If a user of this class tries to build a Person instance but forgot to call either of these methods, we would like to get some kind of warning - either from the java compiler, or maybe from Eclipse or Maven, which we use to build our projects - any of them would do.
Is it possible to do? Which way would you suggest?
Here is an example with using different types to make some parts mandatory (it also makes the order you call the methods mandatory):
package test;
import test.StepOne.StepThree;
import test.StepOne.StepTwo;
import test.StepOne.LastStep;
public class TestBuilder {
public static void main(String[] args) {
String person1 = PersonBuilder.newInstance().head("head").body("body").arm("arm").leg("leg").build();
String person2 = PersonBuilder.newInstance().head("head").body("body").arm("arm").build();
}
}
interface StepOne {
// mandatory
StepTwo head(String head);
interface StepTwo {
// mandatory
StepThree body(String body);
}
interface StepThree {
// mandatory
LastStep arm(String arm);
}
// all methods in this interface are not mandatory
interface LastStep {
LastStep leg(String leg);
String build();
}
}
class PersonBuilder implements StepOne, StepTwo, StepThree, LastStep {
String head;
String body;
String arm;
String leg;
static StepOne newInstance() {
return new PersonBuilder();
}
private PersonBuilder() {
}
public StepTwo head(String head) {
this.head = head;
return this;
}
public LastStep arm(String arm) {
this.arm = arm;
return this;
}
public StepThree body(String body) {
this.body = body;
return this;
}
public LastStep leg(String leg) {
this.leg = leg;
return this;
}
public String build() {
return head + body + arm + leg;
}
}
Edit
The OP was so impressed with this answer that he wrote it up fully in a blog. It's such a clever take on the builder pattern that a full treatment deserves to be referenced here.
I believe the correct use of the builder pattern would solve the issue you're having.
I would create class PersonBuilder which would contain the methods setBody() and setArms() and every other optional parameter setter method. The constructor of the builder would take the required parameters. Then the method build() would return the new instance of Person.
public class PersonBuilder
{
private final Head head;
private Body body;
private Arms arms;
public PersonBuilder(Head head)
{
this.head = head;
}
public void setBody(Body body)
{
this.body = body;
}
public void setArms(Arms arms)
{
this.arms = arms;
}
public Person build()
{
return new Person(head, body, arms);
}
}
Alternatively you could pass the Head parameter to the method build() but I prefer passing it in the constructor instead.
No way with the compiler.
You can do is throw a runtime exception from the build() method that the builder is not properly initialized (and have a test that is invoked in the maven test phase)
But you can also have build(..) accept a HeadDetails object. That way tou can't invoke build without specifying the obligatory parameters.
Why not calling body(), head(), arms() in the build()-Method if it is really mandatory and returning Person in the build() method?
[edit]
Short example:
public class Builder {
private final String bodyProp;
private final String headProp;
private final String armsProp;
private String hearProps;
public Builder(String bodyProp, String headProp, String armsProp) {
super();
this.bodyProp = bodyProp; // check preconditions here (eg not null)
this.headProp = headProp;
this.armsProp = armsProp;
}
public void addOptionalHair(String hearProps) {
this.hearProps = hearProps;
}
public Person build() {
Person person = new Person();
person.setBody(buildBody());
// ...
return person;
}
private Body buildBody() {
// do something with bodyProp
return new Body();
}
public static class Person {
public void setBody(Body buildBody) {
// ...
}
}
public static class Body {
}
}
Maybe inside of build() you could check if all the required methods have been called. Behaps the Person instance has some internal sanity check which is triggered by build().
Of course this checks runtime behaviour and is no static analysis as you describe it.
isn't possible to call these methods in Person's constructor ?