Surendra Anand
Surendra Anand

Reputation: 121

Alternative way to create a class object in java without using a method with class name

I have implemented in such a way below where the class object would be returned and with that I'd be calling the required methods and get the output. To my knowledge, it was appropriate to use. I have recently come across post that suggests that it is bad practice. geeksforgeeks - Post

And I'm looking for an alternate way to implement it.

Main Class:

public class PolymorphismExample {

    public static void main(String[] args) {

        System.out.println("Enter the Role details");
        Scanner scan = new Scanner(System.in);
        String role = scan.nextLine();
        System.out.println((Object)role.getClass().getSimpleName());
        RolesandResponsibilities rr = getRoleLoc(role);
        assert rr != null;
        System.out.println("Role: " + rr.getRole());
        System.out.println("Responsibility: " + rr.getResponsibility());
        scan.close();
    }

    public static RolesandResponsibilities getRoleLoc(String role) {

        switch (role) {
            case "tester":
                return new tester("tester");
            case "developer":
                return new developer("developer");
            case "scrummaster":
                return new scrummaster("scrummaster");
            case "projectmanager":
                return new projectmanager("projectmanager");
            case "intern":
                return new intern("intern");
            default:
                return null;

        }

    }


}

Super Class:

class RolesandResponsibilities {
    String role;

    public RolesandResponsibilities (String role) {
        this.role = role;

    }

    public String getRole() {
        return role;
    }

    public String getResponsibility() {
        return "No responsibility specified";
    }

}

Inherited Sub-Classes:

class developer extends RolesandResponsibilities {

    public developer(String role) {
        super(role);
    }

    public String getResponsibility() {
        return "Develop the application";
    }
}

//Just added only one class as the post is getting lengthy.

Upvotes: 1

Views: 1241

Answers (3)

Gilbert Le Blanc
Gilbert Le Blanc

Reputation: 51445

I prefer magicmn's answer, but I thought I'd illustrate what I said in the comment. As it turns out, I only need to implement one concrete class.

I ran the following test:

Enter the role: 
developer
Role: developer
Responsibility: Develop the application

I created a RolesAndResponsibilities interface. I created a ConcreteClass class based on the interface. I couldn't come up with a better name for the concrete class. I could have stuck an I in front of RolesAndResponsibilities to create the interface name. I see why that's a standard in some Java shops.

I created a createRoleList method to create a java.util.List role list.

The main method became pretty simple after that.

Here's the complete runnable code. I made the additional class and interface inner classes so I could post the code in one block.

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class PolymorphismExample {

    public static void main(String[] args) {
        PolymorphismExample pe = new PolymorphismExample();
        List<RolesAndResponsibilities> roleList = pe.createRoleList();

        Scanner scan = new Scanner(System.in);

        System.out.println("Enter the role: ");
        String role = scan.nextLine();

        for (RolesAndResponsibilities rr : roleList) {
            if (rr.isRole(role)) {
                System.out.println("Role: " + rr.getRole());
                System.out.println("Responsibility: " + 
                        rr.getResponsibility());
                break;
            }
        }

        scan.close();
    }
    
    public List<RolesAndResponsibilities> createRoleList() {
        List<RolesAndResponsibilities> roleList = new ArrayList<>();
        RolesAndResponsibilities rr = new ConcreteClass("developer", 
                "Develop the application");
        roleList.add(rr);
        rr = new ConcreteClass("tester", "Tests the application");
        roleList.add(rr);
        // The rest of the roles go here;
        return roleList;
    }
    
    public class ConcreteClass implements RolesAndResponsibilities {
        
        private final String role, responsibility;

        public ConcreteClass(String role, String responsibility) {
            this.role = role;
            this.responsibility = responsibility;
        }

        @Override
        public boolean isRole(String role) {
            return (this.role.equalsIgnoreCase(role));
        }

        @Override
        public String getRole() {
            return role;
        }

        @Override
        public String getResponsibility() {
            return responsibility;
        }
        
    }
    
    public interface RolesAndResponsibilities {
        public boolean isRole(String role);
        public String getRole();
        public String getResponsibility();
    }

}

Upvotes: 0

magicmn
magicmn

Reputation: 1914

Instead of switch-case you can create a static map. Is that a better solution? It depends.

private static Map<String, RolesandResponsibilities> roles = Arrays.asList(new developer("developer")) // rest of your roles
    .stream()
    .collect(Collectors.toMap(r -> r.getRole(), r -> r));

public static RolesandResponsibilities getRoleLoc(String role) {
    return roles.get(role);
}

But I think you're example has a much bigger problem. What exactly qualifies developer, tester, scrummaster, projectmanager and intern to be their own classes? A class should be the blueprint for objects, what you are doing is creating more blueprints for the things that should be objects.

I would fix this by adjusting RolesAndResposibilities.

public class RolesandResponsibilities {
    private String role;
    private String responsibility;

    public RolesandResponsibilities(String role, String responsibility) {
        this.role = role;
        this.responsibility = responsibility;

    }
    //getter
}

And then just create the objects and add them to a collection.

RolesandResponsibilities none = new RolesandResponsibilities("", "No responsibility specified");
RolesandResponsibilities developer = new RolesandResponsibilities("developer", "Develop the application");
List<RolesandResponsibilities> roles = Arrays.asList(none, developer);
Map<String, RolesandResponsibilities> rolesMap = roles.stream().collect(Collectors.toMap(r -> r.getRole(), r -> r));

Or if you know your roles will not change you can turn RolesandResposibilities into an enum.

public enum RolesandResponsibilities {
    NONE("", "No responsibility specified"), DEVELOPER("developer", "Develop the application");
    
    private String role;
    private String responsibility;

    RolesandResponsibilities(String role, String responsibility) {
        this.role = role;
        this.responsibility = responsibility;

    }

    public String getRole() {
        return role;
    }

    public String getResponsibility() {
        return responsibility;
    }
}

List<RolesandResponsibilities> roles = Arrays.asList(RolesandResponsibilities.values());

Upvotes: 1

Stephen C
Stephen C

Reputation: 718788

To my knowledge, it was appropriate to use.

It isn't. Two reasons:

  1. If you use the same name for a class and a method, it is liable to confuse the reader. For example:

    public class Test {
        public Test() { ... }
        public void Test() { ... }
    }
    

    The reader is liable to misread the Test constructor as a method and vice versa, leading to an incorrect reading of the code in general.

    Even if they do correctly spot the subtle difference, they are liable to be unsure of your intentions. They will question if you made a mistake in writing the code and accidentally declared a method where you meant to declare a constructor. Or vice versa. Even if they come to the conclusion that this is not a mistake, they will have wasted their time working it out.

  2. This is a violation of accepted Java style rules ... which are designed to avoid the above confusion.

    • Java class names must start with an uppercase letter
    • Java method names must start with a lowercase letter

    If a class and method name are the same, then one of them violates the style rules.


The fact that your code is accepted by your IDE and a Java compiler is immaterial. Proper code doesn't just need to work. It also needs to be readable.

Now, you are free to make up your own mind about this, but if you choose to ignore style, expect to get a lot of negative feedback from people who have to read your code.

Upvotes: 3

Related Questions