设计模式仅返回对象中的某些LDAP属性

时间:2015-06-03 14:03:02

标签: java design-patterns ldap

假设我有以下类,包含许多实例变量和相应的getter和setter:

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; }
  ...
}

还有另一个类填充了这些值,而且它是资源密集型的:

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;
    }

}

我有多个客户端想要使用上述类的实例,但是有些客户只对获取变量值的一小部分而不是所有内容感兴趣:

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
    }
}

我能做的一件事就是让客户告诉MyService只检索它感兴趣的值。这样的事情:

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
    }
}

但是,这似乎是错误的,因为其他值将为null。有没有更好的方法来设计它?

编辑:

更具体地说,我正在使用LDAP系统中的用户属性。我不想拥有一个人所有属性的“上帝对象”,而只想撤回每个用例所需的子集。例如,一个应用程序可能需要uid和fullName;另一个可能需要uid,电话号码,小组等。

感谢。

4 个答案:

答案 0 :(得分:3)

一个最简单的解决方案是使用不同的getter集声明几个接口,在类中实现所有这些接口,并使不同的客户端使用不同的接口。

例如

interface A {
    String getA();
}

interface B {
    String getB();
}

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

现在,客户端A使用接口A,只能在客户端B使用接口B时调用getA(),并且只能调用getB()

如果某个客户C必须同时使用A和B,您可以: 1.让它访问两个接口 2.让它直接访问MyClass 3.定义扩展A和B的其他接口C,因此客户端C将使用它。

显然,这个解决方案不是通用的,在某些情况下可能需要定义很多接口。

如果您想要灵活并决定客户端可以在运行时访问的功能集,您可以使用接口,但不能在类中实现它们,而是使用动态代理来包装您的类并公开所需的接口。然而,由于反射调用,该解决方案将工作得更慢。

我可以考虑其他解决方案,但我希望已经写好的内容对你来说已经足够了。

答案 1 :(得分:2)

这闻起来像上帝阶级,或者至多是一个内聚力差的阶级。课程应该具有简单的设计和凝聚力。凝聚力意味着有一个明显的主题(由名称给出),并且方法支持该主题。当你有一个名为“Utilities”的类时,它是一个具有不良内聚力的类的一个很好的例子(由于缺少一个更好的放置它们的地方,很多方法和属性被塞进去)。

您可以根据客户端类的需要refactor the God class或拆分对象并使用组合。

如果您发布了班级的真实姓名(而不是Foo等),我们可以为您提供有关设计的更好的想法。这些细节很重要。

答案 2 :(得分:0)

您需要组合使用Singleton和Facade设计模式。

Singleton只在Foo内保留MyService个对象的一个​​副本。面部将仅为每个所需的数据组合提供getA()getB()等方法。

Client类将调用Facade以获取所需信息。实际上,您可以将My Service作为单身和立面来解决此问题。

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 ....
}

如果您有Foo的多个实现(或)版本,则创建工厂以在Facade内检索正确的版本。

答案 3 :(得分:0)

你可以使用Facade作为Facades和“Adapters”(它们真的不是适配器,只是专门的构建器)来检索数据吗? e.g。

@Html.HiddenFor(x => x.Tags)