成都工程建设项目网站,心理咨询师招聘,wordpress作者增加页面权限,门户网站策划书我相信Joshua Bloch在他的非常好的书“ Effective Java”中首先说了它#xff1a;与构造函数相比#xff0c;静态工厂方法是实例化对象的首选方法。 我不同意。 不仅因为我相信静态方法是纯粹的邪恶#xff0c;而且主要是因为在这种特殊情况下#xff0c;它们伪装成好的方法… 我相信Joshua Bloch在他的非常好的书“ Effective Java”中首先说了它与构造函数相比静态工厂方法是实例化对象的首选方法。 我不同意。 不仅因为我相信静态方法是纯粹的邪恶而且主要是因为在这种特殊情况下它们伪装成好的方法使我们认为我们必须爱上它们。 摘录2009作者麦克·贾奇Mike Judge 让我们从面向对象的角度分析推理并查看其原因。 这是一个具有一个主要构造函数和两个次要构造函数的类 class Color {private final int hex;Color(String rgb) {this(Integer.parseInt(rgb, 16));}Color(int red, int green, int blue) {this(red 16 green 8 blue);}Color(int h) {this.hex h;}
} 这是带有三个静态工厂方法的类似类 class Color {private final int hex;static Color makeFromRGB(String rgb) {return new Color(Integer.parseInt(rgb, 16));}static Color makeFromPalette(int red, int green, int blue) {return new Color(red 16 green 8 blue);}static Color makeFromHex(int h) {return new Color(h);}private Color(int h) {return new Color(h);}
} 你更喜欢哪一个 据约书亚布洛赫但使用静态工厂方法而不是构造函数一共设置了四个但第四个是不是适用于Java的三个基本优势了 他们有名字。 他们可以缓存。 它们可以是子类型。 我认为如果设计错误那么这三者都是完全合理的。 它们是解决方法的好借口。 让我们一一介绍。 他们有名字 这是使用构造函数制作红色番茄颜色对象的方法 Color tomato new Color(255, 99, 71); 这是使用静态工厂方法执行的操作 Color tomato Color.makeFromPalette(255, 99, 71); 看起来makeFromPalette()在语义上比new Color()更丰富对吗 嗯是。 如果我们将它们传递给构造函数谁知道这三个数字意味着什么。 但是“调色板”一词可以帮助我们立即解决所有问题。 真正。 但是正确的解决方案是使用多态和封装以将问题分解为几个语义丰富的类 interface Color {
}
class HexColor implements Color {private final int hex;HexColor(int h) {this.hex h;}
}
class RGBColor implements Color {private final Color origin;RGBColor(int red, int green, int blue) {this.origin new HexColor(red 16 green 8 blue);}
} 现在我们使用正确的类的正确的构造函数 Color tomato new RGBColor(255, 99, 71); 看约书亚 他们可以缓存 假设我在应用程序中的多个位置需要一个红色的番茄色 Color tomato new Color(255, 99, 71);
// ... sometime later
Color red new Color(255, 99, 71); 将创建两个对象这显然是低效的因为它们是相同的。 最好将第一个实例保留在内存中的某个位置并在第二个调用到达时将其返回。 静态工厂方法可以解决这个问题 Color tomato Color.makeFromPalette(255, 99, 71);
// ... sometime later
Color red Color.makeFromPalette(255, 99, 71); 然后在Color内的某个地方我们保留了一个私有静态Map 其中已实例化了所有对象 class Color {private static final MapInteger, Color CACHE new HashMap();private final int hex;static Color makeFromPalette(int red, int green, int blue) {final int hex red 16 green 8 blue;return Color.CACHE.computeIfAbsent(hex, h - new Color(h));}private Color(int h) {return new Color(h);}
} 这是非常有效的性能。 对于像我们的Color这样的小对象问题可能并不那么明显但是当对象较大时其实例化和垃圾回收可能会浪费大量时间。 真正。 但是有一种面向对象的方法可以解决此问题。 我们只是介绍了一个新类Palette 它变成了一个颜色存储区 class Palette {private final MapInteger, Color colors new HashMap();Color take(int red, int green, int blue) {final int hex red 16 green 8 blue;return this.computerIfAbsent(hex, h - new Color(h));}
} 现在我们一次创建一个Palette实例并要求它在每次需要时向我们返回一种颜色 Color tomato palette.take(255, 99, 71);
// Later we will get the same instance:
Color red palette.take(255, 99, 71); 见约书亚没有静态方法没有静态属性。 他们可以亚型 假设我们的Color类有一个lighter()方法该方法应该将颜色转移到下一个可用的打火机上 class Color {protected final int hex;Color(int h) {this.hex h;}public Color lighter() {return new Color(hex 0x111);}
} 但是有时更希望通过一组可用的Pantone颜色选择下一种较浅的颜色 class PantoneColor extends Color {private final PantoneName pantone;PantoneColor(String name) {this(new PantoneName(name));}PantoneColor(PantoneName name) {this.pantone name;}Overridepublic Color lighter() {return new PantoneColor(this.pantone.up());}
} 然后我们创建一个静态工厂方法该方法将决定哪种Color实现最适合我们 class Color {private final String code;static Color make(int h) {if (h 0xBF1932) {return new PantoneColor(19-1664 TPX);}return new RGBColor(h);}
} 如果要求使用真正的红色 我们将返回PantoneColor一个实例。 在其他所有情况下它只是一个标准的RGBColor 。 该决定是通过静态工厂方法做出的。 这就是我们所说的 Color color Color.make(0xBF1932); 由于构造函数只能返回在其中声明的类因此不可能对构造函数进行相同的“分叉”。静态方法具有返回Color任何子类型的所有必要自由。 真正。 但是在面向对象的世界中我们可以而且必须以不同的方式去做。 首先我们将Color为接口 interface Color {Color lighter();
} 接下来我们将将此决策过程移至其自己的类Colors 就像在上一个示例中所做的那样 class Colors {Color make(int h) {if (h 0xBF1932) {return new PantoneColor(19-1664-TPX);}return new RGBColor(h);}
} 而且我们将使用Colors类的实例而不是Color内部的静态方法 colors.make(0xBF1932); 但是这仍然不是真正的面向对象的思维方式因为我们正在将决策权从对象所属的对象转移开。 通过静态工厂方法make()或新类Colors实际上并不重要我们将对象分成两部分。 第一部分是对象本身第二部分是决策算法它位于其他地方。 更加面向对象的设计是将逻辑放入PantoneColor类的对象中该对象将装饰原始的RGBColor class PantoneColor {private final Color origin;PantoneColor(Color color) {this.origin color;}Overridepublic Color lighter() {final Color next;if (this.origin.hex() 0xBF1932) {next new RGBColor(0xD12631);} else {next this.origin.lighter();}return new PantoneColor(next);}
) 然后我们创建一个RGBColor实例并使用PantoneColor装饰它 Color red new PantoneColor(new RGBColor(0xBF1932)
); 我们要求red返回较浅的颜色它返回Pantone调色板中的一种而不是仅在RGB坐标中较浅的颜色 Color lighter red.lighter(); // 0xD12631 当然这个示例是原始的如果我们真的希望它适用于所有Pantone颜色则需要进一步改进 但是我希望您能理解。 逻辑必须保留在类内部 而不是外部静态工厂方法甚至其他补充类中。 当然我在说的是属于这个特定类的逻辑。 如果与类实例的管理有关那么可以有容器和存储就像上面的上一个示例一样。 总而言之我强烈建议您不要使用静态方法尤其是当它们要替换对象构造函数时。 通过其构造函数生成对象是任何面向对象软件中最 “神圣”的时刻请不要错过它的美丽。 您可能还会发现这些相关的帖子很有趣 每个私有静态方法都是新类的候选人 您是一个更好的建筑师您的图表更简单 只有一个主要的建设者 ; 为什么InputStream设计错误 ; 为什么在OOP中很多退货声明是个坏主意 ; 翻译自: https://www.javacodegeeks.com/2017/11/constructors-static-factory-methods.html