假设我有以下类,包含许多实例变量和相应的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,电话号码,小组等。
感谢。
答案 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)