加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – 将字符串的特定“类型”传递给函数的“最佳实践”方法是

发布时间:2020-12-15 05:06:42 所属栏目:Java 来源:网络整理
导读:例如,我有一个有两个字符串的类,其中一个必须设置,另一个可以为null: public class SomeClass{ private String s1; private String s2; ...} 我可以定义一个构造函数如下: public SomeClass(String s1,String s2){ if(s1 == null s2 == null) throw new So
例如,我有一个有两个字符串的类,其中一个必须设置,另一个可以为null:

public class SomeClass{
    private String s1;
    private String s2;

    ...
}

我可以定义一个构造函数如下:

public SomeClass(String s1,String s2){
    if(s1 == null && s2 == null) throw new SomeKindOfException("can't both be null");

    this.s1 = s1;
    this.s2 = s2;
}

我宁愿做一些事情:

public SomeClass(String s1){
    this.s1 = s1;
}

public SomeClass(String s2){
    this.s2 = s2;
}

这显然无法工作,因为它定义了两个采用相同数量和类型的参数的方法.

所以,我想做的事情如下:

public SomeClass(SomeTypeOfString s1){
    this.s1 = s1;
}

public SomeClass(AnotherTypeOfString s2){
    this.s2 = s2;
}

这具有额外的优点,即String的“类型”可以验证它们的内容(例如,SomeTypeOfString必须是6个字符长,而AnotherTypeOfString必须在4到8个字符之间,并且只包含字母数字字符.

此外,它在调用函数时更清楚,应传入哪些数据.

首先,这个概念听起来合情合理吗?

在实现方面,您无法扩展String.你可以把它包起来. String的“类型”本质上是String的类型,因此让它们扩展抽象包装类是有意义的.这可以实现如下:

public abstract class StringWrapper{
    private final String string;

    public StringWrapper(String string){
        this.string = string;
    }

    public String getString(){
        return string;
    }
}

public class SomeTypeOfString extends StringWrapper{
    public SomeTypeOfString(String string){
        super(string);
    }
}

SomeTypeOfString类的代码看起来相当愚蠢,因为它所做的只是定义一个调用超类构造函数的构造函数……但假设你还在那里添加了一些验证,对我来说这看起来很合理.这种实现听起来合理吗?

谁能想到一个更好的概念来解决基本问题,或者更好地实现我概述的概念?

解决方法

您的概念和实现确实看起来很合理,如果一直使用,甚至可以提高可读性.

例如,如果一个“type”字符串表示产品ID,那么您可以生成此类:

public abstract class ProductID{
    private final String id;

    public StringWrapper(String id){
        Preconditions.checkNotNull(id,"Can't construct a ProductID from null");
        Preconditions.checkArgument(isValidId(id),"%s is not a valid Product ID",id);
        this.id = id;
    }

    public String getID(){
        return id;
    }

    public static boolean isValidID(id) {
      // check format
    }

    public boolean equals(Object o) {
        return (o instanceof ProductID && ((ProductID) o).id.equals(this.id));
    }

    public boolean hashCode() {
        return id.hashCode();
    }

    public String toString() {
        return id;
    }
}

请注意,equals()/ hashCode()是必须的,以便能够将ProductID用作Map中的键或确保Set中的唯一性和类似的东西(除了通常有用). toString()可以作为调试工具使用(在这种情况下我可以添加类名,可能使用简洁的MoreObjects.toStringHelper()方法或手动)或者以UI上使用的方式呈现产品ID(其中)如果给定的实现可能没问题.

这有几个好处:

>您知道每个ProductID对象都拥有有效的产品ID(至少在语法上)
>采用ProductID的方法使得该值保持非常明确.如果他们接受字符串而不是那么清楚.
>您可以轻松区分两种仅从其参数类型中获取ID的方法.

不幸的是,我不能说我在任何大型系统中都有使用这种系统的经验(我在较小的系统中使用它很多).但是我看到和/或可以想象的一些缺点是这样的:

>外部API:如果某些代码调用了您,它通常可以处理String,但不能处理ProductID,因此您需要进行转换
>您将需要使用裸字符串值的地方:当用户输入值时,您可能需要能够存储它,即使它不是有效的产品ID.
> mindshare:开发人员需要购买这个概念,真正掌握它并接受它.否则你最终会得到一个丑陋的String / ProductID混合,到处都有大量的转换.

从这三个方面来看,我认为最后一个是最严重的.

但是,如果这对您来说似乎有点过分,那么使用工厂方法而不是构造函数可能是一个解决方案:

public class SomeClass{
    private String s1;
    private String s2;

    private SomeClass(String s1,String s2) {
      Preconditions.checkArguments(s1 != null || s2 != null,"One of s1 or s2 must be non-null!");
      this.s1 = s1;
      this.s2 = s2;
    }

    public static SomeClass fromSomeString(String s1) {
      return new SomeClass(s1,null);
    }

    public static SomeClass fromAnotherString(String s2) {
      return new SomeClass(null,s2);
    }

    public static SomeClass fromStrings(String s1,String s2) {
      return new SomeClass(s1,s2);
    }
}

请注意,我使用Guava Preconditions类来缩短参数检查代码.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读