以下设计的目的是允许String值(实际上)为子类,以便能够建立许多冲突的构造方法(例如,即使参数名称,方法签名也是相同的)不同)。
请考虑以下(非功能性)设计:
Id Interface(空标记界面)
public interface Id {}
类接口(空标记接口)
public interface Classes {}
标题界面(空标记界面)
public interface Title {}
工具类
public Tool(Id id) throws Exception
{
this.span = new Span();
this.span.addAttribute(new Attribute(Attribute.ID, (String)((Object) id)));
}
public Tool(Classes classes) throws Exception
{
this.span = new Span();
this.span.addAttribute(new Attribute(Attribute.CLASS, (String)((Object) classes)));
}
public Tool(Title title) throws Exception
{
this.span = new Span();
this.span.addAttribute(new Attribute(Attribute.TITLE, (String)((Object) title)));
}
public Tool(Id id, Classes classes, Title title) throws Exception
{
this.span = new Span();
this.span.addAttribute(new Attribute(Attribute.ID, (String)((Object) id)));
this.span.addAttribute(new Attribute(Attribute.CLASS, (String)((Object) classes)));
this.span.addAttribute(new Attribute(Attribute.TITLE, (String)((Object) title)));
}
public void Test() throws Exception
{
Tool hammer = new Tool((Id)((Object)"hammer"));
Tool poweredTool = new Tool((Classes)((Object)"tool powered"));
Tool tool = new Tool((Id)((Object)"invention"), (Classes)((Object)"tool powered"), (Title)((Object)"define a new tool"));
}
该方法需要每个参数“type”的接口和从特定接口“type”到Object然后再转换为String的向下转换/向上转换...
我对这种方法感到不舒服,我希望有一种设计模式可以减轻我对子类String的渴望(仅用于构造方法区分的目的)......
我有一个可变方法,它采用任意的名称值对集合来提供固定参数构造函数的替代方法,但上面显示的构造函数是最常见的组合,因此为了方便程序员,他们目前正在考虑如提供......
谢谢!
答案 0 :(得分:5)
考虑一下构造函数的外观,我建议你去除它们并使用Builder pattern代替:
class Tool {
private Tool() { // Preventing direct instantiation with private constructor
this.span = new Span();
}
... // Tool class code
public static Builder builder() {
return new Builder();
}
public static class Builder {
private final Tool tool = new Tool();
public Builder withId(String id) {
tool.span.addAttribute(new Attribute(Attribute.ID, id));
return this;
}
... // other methods in the same manner
public Tool build() {
// Add some validation if necessary
return tool;
}
}
}
用法:
Tool tool = Tool.builder()
.withId("id")
.withClasses("classA, classB")
.build();
答案 1 :(得分:2)
你的基本问题是构造函数有一个固定的名称(类的名称),因此它们必须通过参数类型区分,因此你不能拥有多个具有相同类型但不同解释它们的构造函数。 / p>
有构建器模式(参见其他答案)或者这个 - 工厂方法模式:
// private constructor
private Tool() { }
// factory methods with same parameters but different names:
public static Tool forId(String id) throws Exception {
Tool tool = new Tool();
tool.span = new Span();
tool.span.addAttribute(new Attribute(Attribute.ID, id));
return tool;
}
public static Tool forClasses(String classes) throws Exception {
Tool tool = new Tool();
tool.span = new Span();
tool.span.addAttribute(new Attribute(Attribute.CLASS, classes));
return tool;
}
// etc for other interpretations of a String
你可以重构它以使它更清洁,但这显示了方法的本质。
答案 2 :(得分:1)
我过去使用的是这样的:
public abstract class StringValue {
private final String value;
protected StringValue(String value) { this.value = value; }
public String toString() { return value; }
}
public class Id extends StringValue {
public Id(String id) { super(id); }
}
public class Classes extends StringValue {
public Classes(String classes) { super(classes); }
}
这样,您就可以获得真实的,面向对象的类型。如果您为每种类型都有特定的额外逻辑(验证逻辑,转换逻辑以不同方式表示与不同系统集成的值等),这一功能尤为强大。
如果您不需要额外的逻辑,那么只需要创建几行代码即可。
答案 3 :(得分:0)
最好的解决方案是使用具有不同方法名称的静态工厂方法,如波希米亚的答案所示。
鉴于无法避免超载的假设要求,我们必须提供不同的方法签名;更准确地说,在擦除下不同的签名。因此,有必要定义和使用自定义类型,如Id
等。
一种方法是让方法参数仅用于重载分辨率,而不关心其值:
public Tool(Id id, String value){...}
new Tool( (Id)null, "hammer" );
使用(Id)null
public static final Id ID = null;
new Tool(ID, "hammer");
如果我们要求必须在参数中携带值,则需要包装值的包装类型,如Bolwidt的答案。
在java8中,我们也可以使用lambda表达式来定义包装器:
public interface Id extends Supplier<String>{}
public Tool(Id id)
{
String attributeValue = id.get();
...
}
new Tool((Id)()->"hammer");
new Tool((Id)"hammer"::toString);