OO设计建议 - toString

Yur*_*sev 8 c# java oop coding-style

所以我上了Address课:

class Address 
{
    private String streetAddress;
    private int number;
    private String postalCode;
    private City city;
    private State state;
    private Country country;
}
Run Code Online (Sandbox Code Playgroud)

我想让它的可读版本显示在网格列中.

什么是实现这一目标的最佳和最简洁的方法?

  1. toString类里面的方法Address(我个人不喜欢这种方法,因为'toString'与地址没有直接关系)
  2. ReadableAddressFormatter
    • ReadableAddressFormatter(Address addressToFormat)
    • 上市 String getFormatted()
  3. 以前的类但是getFormmated是静态的,接收Address实例并返回字符串
  4. 其他?建议请.

我正在寻找一个好的设计,专注于清洁代码,解耦可维护性.

Vis*_*ons 7

所有这些方法都已被使用,并且没有办法提供"与上下文无关"的最佳实践.软件工程的最佳答案通常是"它取决于".那就是说,让我们分析一下:

  1. 最好的KISS方法.我这样做是为了我所有的基本"打印到控制台,确保一切正常"的东西.如果你有一个特定的格式,你可以期待地址,这是一个低悬的果实/轻松获胜的解决方案.您可以在一次性情况下始终覆盖此对象或以不同方式打印对象.
  2. 这是最具扩展性的解决方案,因为它很好地允许本地化和自定义格式化.是否合适取决于您希望以不同格式显示地址的频率.你是否真的需要死星来摧毁苍蝇,或者是否能够改变为全部大写或者在对应用程序至关重要的语言之间进行更改?
  3. 我不会建议这种方法,因为它通常开始将"视图级别"逻辑渗透到域中,这通常最好由其他层处理(在类MVC方法中).有人可能认为toString()做同样的事情,但toString()也可以被认为是一个对象如何出现在外部世界的"名称"或"本质",所以我要说它不仅仅是表现.

希望这有助于从一开始就考虑清洁代码,解耦和可维护性.

对于行动中的原则#2的一个例子 - 使用策略模式,遵守单一责任原则,开放/封闭原则并允许通过依赖注入进行控制反转 - 比较以下方法(由@SteveJ慷慨提供) :

public class Address {
        private String streetAddress;
        private int number;
        private String postalCode;
        private String city;
        private String state;
        private String country;

        public String toLongFormat(){
            return null; // stitch together your long format
        }

        public String toShortFormat(){
            return null; // stitch together your short format
        }

        public String toMailingLabelFormat(){
            return null; // stitch together your mailing label format
        }

        @Override
        public String toString(){
            return toShortFormat(); // your default format
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

有了这个(在"大多数正确的"Groovy中):

public interface AddressFormatter {
   String format(Address toFormat)
}

public class LongAddressFormatter implements AddressFormatter {
    @Override
    public String format(Address toFormat){
         return String.format("%sBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAHBLAH%n%s", toFormat.streetAddress, toFormat.postalCode)
    }
}


public class ShortAddressFormatter implements AddressFormatter {
    @Override
    public String format(Address toFormat){
         return String.format("%d", toFormat.number)
    }
}

public  class Address {
        private String streetAddress;
        private int number;
        private String postalCode;
        private String city;
        private String state;
        private String country;
        public  AddressFormatter formatter = new ShortAddressFormatter(); // just to avoid NPE

        public void setFormatter(AddressFormatter fr) { this.formatter = fr; }



        @Override
        public String toString(){
            return formatter.format(this); // your default format
        }
    }

def addrr = new Address(streetAddress:"1234 fun drive", postalCode:"11223", number:1)
addr.setFormatter(new LongAddressFormatter());
println "The address is ${addrr}"
addr.setFormatter(new ShortAddressFormatter());
println "The address is ${addrr}"
Run Code Online (Sandbox Code Playgroud)

正如@SteveJ所观察到的:

"所以你有不同的格式"策略",你可以在它们之间切换......我有这个想法,你会设置格式一次,并坚持下去...如果你想添加另一种格式风格,你不要不必打开并重写地址类,但要编写一个新的单独样式,并在想要使用时注入它."

  • 你可能会遇到`setFormatter()`的竞争条件.我建议将`Address`以`Date`和`DateFormat`的样式传递给`AddressFormatter`,就像`AddressFormatter.format(Address)`. (2认同)

m-y*_*m-y 6

.NET解决方案:

覆盖Object.ToString()似乎是最合乎逻辑的解决方案.这样可以在以下情况下使用它:Console.WriteLine("Home Address: {0}", homeAddress);

如果您希望提供其他格式,则应实现Address类IFormattable.

此外,您应该创建一个实现from IFormatProvider和的AddressFormatter类ICustomFormatter.

MSDN链接提供了非常好的放置示例(BinaryFormatter和AcctNumberFormat),但如果这些还不够,还可以看一下这个好例子:PhoneFormatter


另外,如果您决定全面了解并实现IFormattable和自定义IFormatProvider/ICustomFormatter,那么我建议让ToString()只使用默认提供程序调用ToString(String格式,IFormatProvider formatProvider).这样你就可以解决本地化和地址类型(短,长等)的问题.