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

Design Pattern to only return certain LDAP attributes in an object

假设我有以下 class,有许多实例变量和相应的 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; }
  ...
}

还有另一个 class 填充值,它是资源密集型的:

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

}

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

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

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

编辑:

更具体地说,我正在处理 LDAP 系统中的用户属性。我不想拥有一个人的所有属性的 'God object',我只想提取每个用例所需的子集。例如,一个应用程序可能需要 uid 和 fullName;另一个可能需要 uid、phone 号码、组等

谢谢。

您需要组合使用单例模式和外观设计模式。

Singleton 只在 MyService 中保留一份 Foo 对象。人脸将只提供 getA()getB() 等 ... 方法,用于每个所需的数据组合。

Client class 将调用外观以获取所需信息。事实上,你可以让你的 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.

中检索正确的版本

您可以将接口用作 Facades 和 "Adapters"(它们实际上不是适配器,只是专门的构建器)来检索数据?例如

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

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

例如

interface A {
    String getA();
}

interface B {
    String getB();
}

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

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

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

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

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

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

这闻起来像上帝 Class,或者充其量是 class,但内聚力很差。 Classes 应该具有简单的设计和凝聚力。凝聚力意味着有一个明显的主题(由名称给出)并且方法支持该主题。当你有一个名为 "Utilities" 的 class 时,它是 class 内聚性差的一个很好的例子(很多方法和属性都塞在那里,因为没有更好的地方来放置它们) .

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

如果您发布 class 的真实姓名(而不是 Foo 等),我们将能够为您提供更好的设计思路。这些细节很重要。