Builder (Joshua Bloch-style) for concrete implementation of abstract class? - java

Let's say I have an abstract class (BaseThing). It has one required parameter ("base required") and one optional parameter ("base optional"). I have a concrete class that extends it (Thing). It also has one required parameter ("required") and one optional parameter ("optional"). So something like:
public abstract class BaseThing {
public static final String DEFAULT_BASE_OPTIONAL = "Default Base Optional";
private final String baseRequired;
private String baseOptional = DEFAULT_BASE_OPTIONAL;
protected BaseThing(final String theBaseRequired) {
this.baseRequired = theBaseRequired;
}
final void setBaseOptional(final String newVal) {
this.baseOptional = newVal;
}
public final void selfDescribe() {
System.out.println("Base Required: " + baseRequired);
System.out.println("Base Optional: " + baseOptional);
selfDescribeHook();
}
protected abstract void selfDescribeHook();
}
and:
public final class Thing extends BaseThing {
public static final String DEFAULT_OPTIONAL = "Default Optional";
private final String required;
private String optional = DEFAULT_OPTIONAL;
Thing(final String theRequired, final String theBaseRequired) {
super(theBaseRequired);
required = theRequired;
}
#Override
protected void selfDescribeHook() {
System.out.println("Required: " + required);
System.out.println("Optional: " + optional);
}
void setOptional(final String newVal) {
optional = newVal;
}
}
I want to have a Joshua Bloch-style builder for Thing objects. More generally, though, I want to make it easy for concrete implementations of BaseThing to have builders, so what I really want (I think) is a BaseThing builder that can easily be used to make a ThingBuilder, or an OtherThingBuilder, or a SuperThingBuilder.
Is there a better way than the following that I've come up with (or are there problems with what I've come up with)?
public abstract class BaseThingBuilder<T extends BaseThing> {
private String baseOptional = BaseThing.DEFAULT_BASE_OPTIONAL;
public BaseThingBuilder<T> setBaseOptional(final String value) {
baseOptional = value;
return this;
}
public T build() {
T t = buildHook();
t.setBaseOptional(baseOptional);
return t;
}
protected abstract T buildHook();
}
and:
public final class ThingBuilder extends BaseThingBuilder<Thing> {
private final String baseRequired;
private final String required;
private String optional = Thing.DEFAULT_OPTIONAL;
public ThingBuilder(final String theRequired,
final String theBaseRequired) {
required = theRequired;
baseRequired = theBaseRequired;
}
public ThingBuilder setOptional(final String value) {
optional = value;
return this;
}
protected Thing buildHook() {
Thing thing = new Thing(required, baseRequired);
thing.setOptional(optional);
return thing;
}
}
Which can be used to build Thing objects in a manner similarly to the following:
BaseThingBuilder<Thing> builder =
new ThingBuilder("Required!", "Base Required!")
.setOptional("Optional!")
.setBaseOptional("Base Optional!");
Thing thing = builder.build();
thing.selfDescribe();
Which outputs:
Base Required: Base Required!
Base Optional: Base Optional!
Required: Required!
Optional: Optional!
One issue that I know about, but that I don't consider particularly important (though if it can be improved it would be nice to do so) is that you have to set all non-base options before you set any base option: Doing otherwise would result in a syntax error, as setBaseOptional() returns a BaseThingBuilder rather than a ThingBuilder.
Thanks in advance.

I don't think it's a good idea to think of builders that way. A hierarchy of builders usually leads to headaches and fragile code.
Cutting down the amount of code that needs to be written in the concrete builders and reusing logic from the base builder is closely tied to the domain. It's not easy to develop a general solution. But, let's try to go through an example anyway:
public interface Builder<T> {
T build();
}
public class Person {
private final String name;
//the proper way to use a builder is to pass an instance of one to
//the class that is created using it...
Person(PersonBuilder builder) {
this.name = builder.name;
}
public String getName(){ return name; }
public static class PersonBuilder implements Builder<Person> {
private String name;
public PersonBuilder name(String name){ this.name = name; return this; }
public Person build() {
if(name == null) {
throw new IllegalArgumentException("Name must be specified");
}
return new Person(this);
}
}
}
Groovy, baby! Now what? Maybe you want to add a class to represent a student. What do you do? Do you extend Person? Sure, that's valid. How about taking a more "strange" route and attempting aggregation? Yep, you can do that too... Your choice would have an affect on how you will end up implementing builders. Let's say you stick to the traditional path and extend Person (you should already starting asking yourself, does it make sense for Person to be a concrete class? If I make it abstract, do I really need a builder? If the class is abstract should the builder be abstract?):
public class Student extends Person {
private final long id;
Student(StudentBulder builder) {
super(builder);
this.id = builder.id;
}
public long getId(){ return id; }
//no need for generics, this will work:
public static class StudentBuilder extends PersonBuilder {
private long id;
public StudentBuilder id(long id){ this.id = id; return this; }
public Student build() {
if(id <= 0) {
throw new IllegalArgumentException("ID must be specified");
}
return new Student(this);
}
}
}
Ok, this looks exactly like what you wanted! So, you try it:
Person p = new PersonBuilder().name("John Doe").build();
Student s = new StudentBuilder().name("Jane Doe").id(165).build();
Looks great! Except, it doesn't compile... There's an error at line 2 and it states The method id(int) is undefined for the type Person.PersonBuilder. The problem is that PersonBuilder#name returns a builder of type PersonBuilder, which isn't what you want. In StudentBuilder you actually want the return type of name to be StudentBuilder. Now, you think ahead and realize that if anything extends StudentBuilder you'd want it to return something else entirely... Is that doable? Yes, with generics. However, it's ugly as hell and introduces quite a bit of complexity. Therefore, I refuse to post the code that illustrates it, for the fear that someone will see this thread and actually use it in their software.
You might think rearranging method calls will work (calling id before calling name): new StudentBuilder().id(165).name("Jane Doe").build(), but it won't. At least not without an explicit cast to Student: (Student)new StudentBuilder().id(165).name("Jane Doe").build() since, in this case, PersonBuilder#build is being called which has a return type of Person... This is simply unacceptable! Even if it worked without an explicit cast, it should make you wince to know that a builder's methods must be called in a certain order. Because if you don't, something won't work...
There are many more problems that would arise if you continue trying to get it to work. And even if you did get it to work, I don't think it would be easily comprehensible and certainly not elegant. Of course, feel free to prove me wrong and post your solution here.
By the way, you should also ask yourself what is an abstract builder? Because, it sounds like an oxymoron.
In the end, I believe that the scope of this question is too great. The answer is domain-specific and hard to come up with in the absence of your requirements. Just remember, the general guideline for builders is to have them be as simple as possible.
Also, take a look at a related question.

As far as I can tell if you remove the generics then
BaseThingBuilder<Thing> builder =
new ThingBuilder("Required!", "Base Required!")
changes to
BaseThingBuilder builder =
new ThingBuilder("Required!", "Base Required!")
The rest of it all remains same, including the restriction that subclass has to be initialized first. So I really don't think this warrants use of generics. Maybe I am missing something.
I seem to remember something like this from Bjarne Stroustrup, long back...

Related

How to return an object from different classes in Java?

I'm beginner in Java and I need help. I have several classes.
public class A{
private String name = "A";
public String getClassName(){
return "A";
}
public void editClassName(String name){
this.name = name;
}
}
public class B{
private String name = "B";
private int counter = 0;
public String showClassName(){
return "B";
}
public int getCount(){
return counter;
}
}
Such classes could be more. I also need to have some class witch can return an instance of asked class.
public class ClassSelector{
public static ??? getClassByName(String nameOfClass){
if(nameOfClass == "A"){ return new A();}
if(nameOfClass == "B"){ return new B();}
}
}
And here is a code that I want to use to get access to appropriate class:
ClassSelector.getClassByName("A").getClassName();
ClassSelector.getClassByName("B").showClassName();
I need to have an access to the instance of the class, and each instance can show it's unit methods that class has.
In this situation I don't get which return type I should use in the 'getClassByName' method.
I will very appreciate for help.
I would very much like to offer an alternative architecture if possible! It's not much different to what you have.
Firstly, we'll define some interface.
public interface Named {
String getName();
}
Now, this means you can have lots of concrete classes but provided they implement this interface, you'll know (and the Java compiler will know) that they have the getName method available to you.
Next, let's update your class to implement this interface.
public class A implements Named {
public String getName() {
return "A";
}
}
You could do this for classes B, C... and so on.
Now your method return type can be set to Named, that is:
public class ClassSelector{
public static Named getClassByName(String nameOfClass){
if(nameOfClass.equals("A")){ return new A();}
if(nameOfClass.equals("B")){ return new B();}
}
}
And you can access the response like so:
Named response = ClassSelector.getClassByName("A").getName();
As Eran suggested, it can be only of type Object, because they don't have a common superclass other than Object. If you don't want to work with Object class, you can create a body-less interface and implement it in both(or multiple classes) and that can be your return type.
After the call of the method, you can find the specific type of the returned object with instanceof;
What you are trying to do is called the Factory Pattern.
Assuming you are crating Widgets I suggest;
Introduce a Widget interface and have A and B implement Widget as per Christopher’s answer
Rename ClassSelector to WidgetFactory
Rename the method getClassByName to create, make it non-static and return Widget instances
This is more aligned with common Java name conventions and thus makes your code readily understandable by most developers.
If you want to keep your factory static it is of course possible but it may make your code less testable as it cannot be switched out for another factory in your tests. This is problematic if A and B are heavy weight objects that carries a lot of external dependencies that you may want to exclude.
If testability is a concern you may even consider making the factory implement a WidgetFactory interface...
First of all, please note that for string comparison you have not to use "==" (the problem is in nameOfClass == "A" and so on, I say it only for completeness).
I want suggest a solution based on reflection, that maybe could be more concise:
public interface IClass {
}
public class A implements IClass {
private String name = "A";
}
public class B implements IClass {
private String name = "B";
}
public class ClassSelector {
public static void main(String[] args) {
IClass obj = null;
try {
Class c = Class.forName("A");
obj = (IClass) c.newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
System.out.println("Create object of type " + obj.getClass());
}
}
Thanks to all guys, who have answered my. Forgive me, when I create the first post, I made one mistake, which leads to misunderstanding what I mean. Now the code in the first post is better to show what I'm looking for.

How to drop property with its value in Java?

I am so new to Java world so please be kind.
I have one class which has some properties as below:
public class Test{
private long prop1;
private long prop2;
public long getProp1() {
return prop1;
}
public void setProp1(long prop1) {
this.prop1= prop1;
}
public long getProp2() {
return prop2;
}
public void setProp2(long prop2) {
this.prop2 = prop2;
}
}
Now I am after some operation I have filled object of class Test which is going to be sent to oData for save purpose. Somehow I do not want prop2 to be inserted into the string which will go to oData call, so how can I drop prop2 along with its value?
[prop1=1, prop2=2]
You will need a method that elaborate that for you,
one option can be define a method and print the properties as you need...
you can as orientation, take a look to this autogenerated toString method
#Override
public String toString() {
return "_Foo [prop1=" + prop1 + ", prop2=" + prop2 + "]";
}
remove the _Foo part and there you are!
thing is I require prop2 till one level to perform some operation but I need to remove it just before oData call, is it possible?
Not that I am aware of. Also, I don't know oData and your question is a bit hard to answer with the little info you provided. However, based on the above comment, I'm going to suggest two things:
Approach #1: Reduced Class
public class Test {
private long prop1;
private long prop2;
/* getters, setters, ...*/
}
public class TestReduced {
private long prop1;
public TestReduced(Test test) {
this.prop1 = test.getProp1();
}
/* getters, setters, ...*/
}
In other words, create a class that is similar to Test, bar the undesired member. In its constructor, copy every other member of the handed in Test object, effectively creating a copy that can be used for oData:
Test test1 = new Test();
test1.setProp1(1337L);
test1.setProp2(1007L);
/* Do something with test1, including prop2 */
TestReduced test2 = new TestReduced(test1);
/* Do oData stuff with test2, no prop2 anymore */
That's a pretty convoluted solution and it requires you to mirror all changes to Test in TestReduced. A common interface or an abstract base class could safeguard this process quite well, so I would definitely recommend putting one into place if you go with this. You should also consider adding a private constructor without parameters for TestReduced to make sure those can only be created from Test objects. Alternatively, let the Test class create instances of TestReduced with a method like getReducedInstance(), which would make Test a factory.
Approach #2: Member Map
How about, instead of having two members, prop1 and prop2, you use a Map?
public class Test {
private HashMap<String, Long> props = new HashMap<>();
public Test() {
props.put("prop1", 0L);
props.put("prop2", 0L);
}
public void setProp1(long prop1) {
props.put("prop1", p);
}
public void setProp2(long prop2) {
props.put("prop2", p);
}
public long getProp1() {
props.get("prop1");
}
public long getProp2() {
props.get("prop2");
}
public void prepareForSerialization() {
props.remove("prop2");
}
}
Whether this works with oData, I don't know. But it surely is a pretty flexible way to handle an arbitrary number of properties. With your getters and setters, you can hide the implementation (HashMap vs. primitive type memebers). Or, if you prefer, you can expose it to the user by providing methods like getProp(String name) and setProp(String name, long value). All of this is assuming that all your props are of type long.
Obviously, it would be better if you just had two methods for your serialization (?) purposes, one that includes prop1, one that doesn't. But since you explicitly said that you need to remove a member, this is what comes to my mind.

Is there any way to access this.toString()'s value when calling another constructor?

For everyone who is talking about the fact that the object is in an "unitialized state", please refer to the answer to this question which shows that an object reference can be passed around, dereferenced, have methods invoked from it, and have fields accessed before a constructor terminates and all fields have been assigned (including final fields).
So here's the use case:
public class Entity {
private final String name;
public Entity() {
this(toString()); //Nope, Chuck Testa
}
public Entity(String name) {
this.name = name;
}
}
The compiler error is:
Cannot refer to an instance method while explicitly invoking a constructor.
Note that toString() has not been overriden and is the default call from Object.
I'm certainly interested in the philosophical/technical reasons behind this, so if anyone can explain that, that would be an awesome bonus. But I'm looking for a way to call toString() from that default constructor as it refers down to the more specific one with more arguments. The actual use case is a bit more complicated and ends up referring all the way down to a constructor with four arguments, but that shouldn't really matter.
I know I could do something like this...
private static final String TO_STRING_CONSTRUCTOR_ARGUMENT = "aflhsdlkfjlkswf";
public Entity() {
this(TO_STRING_CONSTRUCTOR_ARGUMENT);
}
public Entity(String name) {
this.name = name == TO_STRING_CONSTRUCTOR_ARGUMENT ? toString() : name;
}
... but it seems like a pretty inelegant solution.
So, any way to pull it off? Or any recommended best practices to deal with this situation?
I would prefer not to pass this around until the object is created. Instead I would do this:
public class Entity {
private final String name;
public Entity() {
this(null); // or whatever
}
public Entity(String name) {
this.name = name;
}
public String getName() {
return name != null ? name : Objects.hashCode(this);
}
}
If you can live without the final name, you can use an initializer block:
public class Entity {
private String name;
{name = this.toString();}
public Entity() {
}
public Entity(String name) {
this.name = name;
}
}
this is only available after all calls to this() or super() are done. The initializer runs first after the constructors call to super() and is allowed to access this.
As for the reasons why that is a compiler error, please see section 8.8.7 of the JLS. The reasons why this was made a compiler error are not clear, but consider that the constructor chain has to be the first thing executed when new'ing an Object and look at the order of evaluation here:
public Entity() {
this(toString());
}
toString() is evaluated first before the even the super constructor is invoked. In general this leaves open all kinds of possibilities for uninitialized state.
As a personal preference, I would suggest that everything an object needs to have in order to create valid state should be available within its constructor. If you have no way of providing valid state in a default constructor without invoking other methods defined in the object hierarchy, then get rid of the default constructor and put the onus on the users of your class to supply a valid String to your other constructor.
If you are ultimately just trying invoke the other constructor with the value of toString(), then I would suggest the following instead:
public Entity() {
name = toString();
}
which accomplishes the same goal you set out to achieve and properly initializes name.
As explained in the JLS this is not allowed before the instance is initialized.
However, there are ways to handle your scenario in a consistent manner.
As I see your case, you want to signify either a generated value (toString()) or a user provided value, which can be null.
Given this constraints, using TO_STRING_CONSTRUCTOR_ARGUMENT is failing for at least one specific use case, however obscure it may be.
Essentially you will need to replace the String with an Optional similar to what exists in Google Guava and will be included in Java 8, and seen in many other languages.
Having a StringOptional/StringHolder or whatever you choose, similar to this:
public class StringOptional {
private String value;
private boolean set = false;
public StringOptional() {}
public StringOptional(String value) {
this.value = value;
this.set = true;
}
public boolean isSet() { return set; }
public String getValue() { return value; }
}
Then you can call constructors with the knowledge of the inferred path.
public class Entity {
public Entity() {
this(New StringOptional());
}
public Entity(String s) {
this(new StringOptional(s));
}
private Entity(StringOptional optional) {
super(optional);
}
}
And store this for subsquent need:
if (optional.isSet() ? optional.getValue() : toString();
This is how I usually would handle a maybe-null scenario, hope it augments as an answer.
You cannot 'use' an instance that has not been created yet. By calling a second constructor you are postponing the creation, you cannot use it before the call or in the action of calling.
You can use a static method factory in your class Entity, and put the constructor private:
public class Entity {
private String name;
private Entity() {
}
public Entity(String name) {
this.name = name;
}
public static Entity createEntity() {
Entity result = new Entity();
result.name = result.toString();
return result;
}
}

Generic Type From Enum & The Builder Pattern

I'm trying to create a builder pattern that uses generics to provide type checking on some of the methods. Currently I have the following working:
ParameterBuilder.start(String.class).setName("foo").setDefaultValue("Hello").build();
ParameterBuilder.start(Integer.class).setName(bar).setDefaultValue(42).build();
ParameterBuilder.start(Boolean.class).setName(bar).setDefaultValue(false).build();
Using the code:
public class ParameterBuilder<T> {
private String name;
private T defaultValue;
public static <T2> ParameterBuilder<T2> start(Class<T2> type) {
return new ParameterBuilder<T2>();
}
// Other methods excluded for example
}
So the type of the input for the setDefaultValue method is defined by what's passed into the start method, just as I want.
But now I want to extend what's being passed into start() to contain a little more information. Essentially I want to pass in a "type" for the parameters I creating. Sometimes these parameters will be things like "email", "url" etc. The default value will still be of a known type (String in those cases), so I'd like to have something like:
ParameterBuilder.start(EMAIL).setName("email").setDefaultValue("foo#bar.com").build();
ParameterBuilder.start(URL).setName("website").setDefaultValue("http://www.somewhere.com").build();
Where at the moment EMAIL & URL are enums, containing amongst other things - the class of the default value. But if I go down this route, how would I instantiate the parameter builder?
public static <T2> ParameterBuilder<T2> start(ParameterType paramType) {
Class<T2> type = paramType.getTypeClass();
// How do I instantiate my ParameterBuilder with the right type?
}
If it can't be done using enums (which I can see being the case), does anyone have a suggestion for a different solution?
I think you need one enum per class type (I don't see how you could have one enum cover several types and keep the thing working). In that case, a common generic interface could do what you want. You can then create some sort of factory to provide the enum constants if that helps.
This compiles:
static interface ParameterType<T> {}
static enum ParameterTypeEnum implements ParameterType<String> { EMAIL; }
public static void main(String[] args) {
ParameterBuilder
.start(ParameterTypeEnum.EMAIL)
.setName("email")
.setDefaultValue("foo#bar.com")
.build();
}
public static class ParameterBuilder<T> {
private String name;
private T defaultValue;
public static <T2> ParameterBuilder<T2> start(ParameterType<T2> paramType) {
return new ParameterBuilder<T2>();
}
ParameterBuilder<T> setName(String name) {
this.name = name;
return this;
}
ParameterBuilder<T> setDefaultValue(T defaultValue) {
this.defaultValue = defaultValue;
return this;
}
void build() {}
}
I'm not sure the context in what you want to use this, but I think the following might be an option.
You can follow the Open/Closed principle and create an interface Parameter and have one implementation per type. The benefit of this, is that you don't need to add a new enum value for each new Parameter you want. You can later pass the class to ParameterBuilder rather than the enum and the ParameterBuilder and Parameter would work together to build what you need.
So ParameterBuilder.start() could return an instance of the specific Parameter and the parameter might have different methods depending on the type of parameter.
I don't think this answer is really good, but hopefully can give you a hint in how to build a potential solution for your context.
You could create an object hierachie for these Email and Url types
public class DefaultType {
protected String name;
protected String defaultValue;
//some constructor
}
public class EmailType extends DefaultType {
...
}
public class URLType extends DefaultType {
...
}
then the parameter builder could look something like this:
public static ParameterBuilder start(DefaultType type) {
ParameterBuilder builder = new ParameterBuilder(type);
builder.setType(type);
return builder;
}
Then you could call it like this:
ParameterBuilder.start(new EmailType("name","value");...
does this help or dont you want to go in this direction?

Handling more than 7 Parameters

I have a public class, which needs 7 parameters to be passed down. At the moment, I am able to make 3 of them being passed to constructor and another 4 to a public method in the class . Like this:
Public Class AClass{
private XClass axClass;
private String par4;
private String par5;
private String par6;
private String par7;
public AClass(String par1, String par2, String par3){
aXClass = new XClass(par1,par2,par3);
}
public execute(String par4,String par5, String par6, String par7){
//this is needed because they are used in other private methods in this class
this.par4 = par4;
this.par5 = par5;
this.par6 = par6;
this.par7 = par7;
//call other private methods within this class.
//about 7 lines here
}
}
My question is, is this the right way to ask client of the class to passing in paramters?
There shouldn't be anything stopping you from passing 7 parameters to a constructor, if that's what you want. I don't know if there's a maximum number of parameters that can be passed to a method in Java, but it's certainly higher than 7 if there is a max.
When you create a class and its public methods, you're creating an interface on how to use and access that class. So technically what you've done so far is correct. Is it the "right way" to ask the client of a class to pass in arguments? That's up to you, the designer of the interface.
My first instinct when I saw 7 parameters being passed was to silently ask "Is there some relationship between some or all of these parameters that might mean they'd go together well in a class of their own?" That might be something you address as you look at your code. But that's a question of design, not one of correctness.
I'd go for the Builder Pattern instead of many constructor parameters as suggested by
Effective Java Item 2: Consider a builder when faced with many constructor parameters
Here's a simple class to illustrate:
public class Dummy {
private final String foo;
private final String bar;
private final boolean baz;
private final int phleem;
protected Dummy(final Builder builder) {
this.foo = builder.foo;
this.bar = builder.bar;
this.baz = builder.baz;
this.phleem = builder.phleem;
}
public String getBar() {
return this.bar;
}
public String getFoo() {
return this.foo;
}
public int getPhleem() {
return this.phleem;
}
public boolean isBaz() {
return this.baz;
}
public static class Builder {
private String foo;
private String bar;
private boolean baz;
private int phleem;
public Dummy build() {
return new Dummy(this);
}
public Builder withBar(final String bar) {
this.bar = bar;
return this;
}
public Builder withBaz(final boolean baz) {
this.baz = baz;
return this;
}
public Builder withFoo(final String foo) {
this.foo = foo;
return this;
}
public Builder withPhleem(final int phleem) {
this.phleem = phleem;
return this;
}
}
}
You would instantiate it like this:
Dummy dummy = new Dummy.Builder()
.withFoo("abc")
.withBar("def")
.withBaz(true)
.withPhleem(123)
.build();
The nice part: you get all the benefits of constructor parameters (e.g. immutability if you want it), but you get readable code too.
Can't you just make a class/hashmap that stores these parameters and pass this to the function?
public excute(Storageclass storageClass){
//this is needed because they are used in other private methods in this class
this.par4 = storageClass.getPar4();
this.par5 = storageClass.getPar5();
this.par6 = storageClass.getPar6();
this.par7 = storageClass.getPar7();
//or
this.storageClass = storageClass;
}
I don't really see the problem with that.
In any case you could create a "Request" object or something like this:
class SomeClass {
private String a;
private String b;
....
public SomeClass( Request r ) {
this.a = r.get("a");
this.b = r.get("b");
...
}
public void execute( Request other ) {
this.d = other.get("d");
this.e = other.get("d");
...
}
}
See also: http://c2.com/cgi/wiki?TooManyParameters
Without knowing the use of the child class, I can say that there is nothing inherently wrong with what you have done.
Note though that you have to declare
private XClass axClass;
in the variables of your AClass.
However, you say 'I am able to make....' Does this mean there is some problem with declaring this another way?
I don't care for it much, because an object should be 100% ready to be used after its constructor is called. It's not as written in your example.
If the parameters passed into the execute method can simply be consumed, and that's the method of interest for clients, I see no reason for them to be data members in the class.
Without knowing more about your ultimate aims it's hard to tell. But I would re-think this implementation.
If you're planning on introducing an AClass.someMethod() that needs to know par4-7 without requiring you to have called AClass.excute(), then clearly you should be passing the parameters in the constructor.
On the other hand: if you can construct an instance of this object with only par1-3 and do something meaningful with it besides call excute() then it makes sense to allow the object to be constructed with fewer than the full seven parameters.
Yet my own aesthetic is to try and limit the number of "modes" that an object can be in which make certain methods work and others fail. So ideally, a fully-constructed object is ready to run any method the programmer might call. I'd worry about the design issue more than be too concerned about the sheer number of parameters to the constructor.
But as others have pointed out, sometimes there is a natural grouping of these parameters which can deserve objects of their own. For instance: in many APIs instead of passing (x, y, width, height) all over the place they use rectangle objects.
As others already wrote, it is technically correct to pass 7 parameters, although not very 'user-friendly', if you can say so.
Since you didn't write much about this class, I can suggest one small thing: in constructor you're just creating XClass object, so it would be sane to create this object before and pass it as a single parameter.
Something like this:
...
XClass aXClass = new XClass(par1, par2, par3);
AClass aClass = new AClass(aXClass);
...
And this is the constructor:
public AClass(XClass aXClass) {
this.aXClass = aXClass;
}

Categories

Resources