3

Let's say I have the following class, with many instance variables and corresponding getters and setters:

public class Foo {
  private String a;
  private int b;
  ...
  private List<String> z;

  public String getA() { return a; }
  public void setA(String a) { this.a = a; }
  public int getB() { return b; }
  public void setB(int b) { this.b = b; }
  ...
}

There is another class that populates the values, and it's resource intensive:

public class MyService {

    public Foo retrieveFoo() {
        // call some resource intensive code to retrieve the values
        String a = getTheString();
        int b = getTheInt();
        List<String> z = getTheList();

        Foo f = new Foo();
        f.setA(a);
        f.setB(b);
        ...
        f.setZ(z);

        return f;
    }

}

I have multiple clients that want to use instances of the above class, but some are only interested in getting a small subset of the variable values and not everything:

public class ClientA {
    private MyService service;

    public void doSomething() {
        Foo f = service.retrieveFoo();
        String a = f.getA();
        int b = f.getB();
        // not interested in anything else
    }
}

 public class ClientB {
    private MyService service;

    public void doSomething() {
        Foo f = service.retrieveFoo();
        List<String> z = f.getZ();
        // not interested in anything else
    }
}

One thing I could do is have the client tell the MyService to only retrieve which values it's interested in. Something like this:

public class ClientA {
    private MyService service;

    public void doSomething() {
        // the Service would only retrieve a and b, which 
        // means all other variables would be set to Null
        Foo f = service.retrieveFoo(Arrays.asList("a","b"));
        String a = f.getA();
        int b = f.getB();
        // not interested in anything else
    }
}

However, this just seems wrong since the other values would be null. Is there a better way to design this?

EDIT:

To be more specific, I'm working with user attributes in an LDAP system. Instead of having a 'God object' of all of a person's attributes, I'd like to only have to pull back the subset that I need for each use case. For example, one application might need uid and fullName; another might need uid, phone number, groups, etc.

Thanks.

acvcu
  • 2,476
  • 10
  • 40
  • 56
  • you could use factory, create FooFactory interface, and for each client use different implementation – user902383 Jun 03 '15 at 14:10
  • What about dividing `Foo` into multiple subclasse, each derived from a common class, that only have certain sets of instance variables, teach the provider to populate those subclasses, and have the clienets request the respective subclass? – cgogolin Jun 03 '15 at 14:10

4 Answers4

3

One simplest solution is to declare several interfaces with different set of getters, implement all of them in your class and make different clients to work with different interfaces.

For example

interface A {
    String getA();
}

interface B {
    String getB();
}

class MyClass implements A, B {
    String getA() {...}
    String getB() {...}
}

Now client A works with interface A and can only call getA() while client B works with interface B and can only call getB().

If some client C has to operate with both A and B you can either: 1. get it access to both interfaces 2. get it access to the MyClass directly 3. define other interface C that extends A and B, so client C will work with it.

Obviously this solution is not generic and can require definition of a lot of interfaces in some cases.

If you want to be flexible and decide about the set of features that client can access at runtime you can use interfaces, but not implement them in your class but use dynamic proxy to wrap your class and expose required interface. This solution however will work slower due to reflection calls.

There are other solutions I can think about but I hope that already written here are good enough for you.

AlexR
  • 114,158
  • 16
  • 130
  • 208
  • I like this idea, because it is the first step in redesigning (refactoring) the bloated `MyClass`, which is really the source of the problem. – Fuhrmanator Jun 04 '15 at 18:01
2

This smells like a God Class, or at best a class that has bad cohesion. Classes should have simple designs and be cohesive. Cohesion means there's a theme that's obvious (given by the name) and that the methods suppor that theme. When you have a class named "Utilities" it's a great example of a class with bad cohesion (a lot of methods and attributes get crammed in there for lack of a better place to put them).

You could refactor the God class or break up the objects and use composition according to the needs of the client classes.

If you posted the real names of your class (instead of Foo, etc.) we'd be able to give you better ideas about the design. Those details matter.

Community
  • 1
  • 1
Fuhrmanator
  • 11,459
  • 6
  • 62
  • 111
  • I added additional details. In essence I'm working with getting user attributes back from our LDAP system and don't want to pull back everything for a user when the use case doesn't call for it. – acvcu Jun 05 '15 at 17:23
  • You're not the first to encounter this trouble. I saw your edit. It's really important to put LDAP in the question, even the title. http://www.informit.com/articles/article.aspx?p=28786 – Fuhrmanator Jun 07 '15 at 15:43
0

You need a combination of Singleton and Facade design patterns.

The Singleton is to keep only one copy of Foo object inside MyService. The face will provide only getA(), getB() etc ... methods for each required combination of the data.

Client class will call the facade to get the required information. In-fact you can make your My Service as both singleton and facade to solve this.

class MyService{
   private static Foo foo;
   private MyService(){}
   static{
      foo = initFoo(); // initialize the Foo object
   }

   // Now provide the facade api for each required combination

  static getA(){return foo.getA();}
  static getB(){return food.getB();}
  // etc ....
}

if you have multiple implementations (or) versions of the Foo, then create a Factory to retrieve correct version inside your Facade.

K139
  • 3,654
  • 13
  • 17
0

You could use interfaces as Facades and "Adapters" (they really aren't adapters, just specialized builders) to retrieve the data? e.g.

interface IFooA {
   A getA();
}

interface IFooB {
   B getB();
}

public class Foo implements IFooA, IFooB {
  // ....
}

public class MyService {
  // code not optimized for brevity!

   public IFooA retrieveFooA() {
        return new IFooAAdapter().getOnlyIFooASubset();
   }

   public IFooB retrieveFooB() {
        return new IFooBAdapter().getOnlyIFooBSubset();
   }
francesco foresti
  • 2,004
  • 20
  • 24
  • Facade makes a "complex subsystem of classes" easier to use. The problem here is that the Foo class is acting like a "complex subsystem of classes". That is not what a class is supposed to be. – Fuhrmanator Jun 04 '15 at 18:03