简体   繁体   English

静态工厂方法的现实用例?

[英]Realistic use case for static factory method?

I'm familiar with the idea and benefits of a static factory method, as described in Joshua Bloch's Effective Java : 我熟悉静态工厂方法的想法和好处,如Joshua Bloch的Effective Java中所述

  • Factory methods have names, so you can have more than one factory method with the same signature, unlike constructors. 工厂方法具有名称,因此与构造函数不同,您可以使用多个具有相同签名的工厂方法。
  • Factory methods don't have to create a new object; 工厂方法不必创建新对象; they can return a previously-created object. 他们可以返回以前创建的对象。 This is good for immutable objects or value objects. 这适用于不可变对象或值对象。
  • Factory methods can return an object of any subtype of their return type, unlike constructors. 与构造函数不同,工厂方法可以返回其返回类型的任何子类型的对象。

Now I'm trying to explain static factory methods for someone who is learning Java and OO principles. 现在,我正在尝试为正在学习Java和OO原则的人解释静态工厂方法。 She learns best from concrete scenarios instead of abstractions. 她从具体场景而不是抽象中学习得最好。 If she can see the pattern at work, solving some problem, she'll get it. 如果她能看到工作模式,解决一些问题,她就会明白。 But she finds it harder to read an abstract list of characteristics like the above to understand how to apply the pattern. 但她发现更难以阅读上述特征的抽象列表来理解如何应用模式。

Can you help me come up with a realistic example of using a static factory method, that makes its benefits clear, but which is still simple enough to show someone in an introductory Java class? 你能帮我提出一个使用静态工厂方法的现实例子,它可以使它的好处变得清晰,但是它仍然足够简单,可以在介绍性的Java类中显示某些人吗?

This person does have programming experience in PL/SQL but never got around to learning OOP patterns. 这个人确实有PL / SQL的编程经验,但从来没有学过OOP模式。

Use javax.swing.BorderFactory as an example of all three points. 使用javax.swing.BorderFactory作为所有三个点的示例。

This class is used to make borders for swing objects. 此类用于为swing对象创建边框。 These border objects can be easily re-used, and this factory method allows for this. 这些边框对象可以很容易地重复使用,这种工厂方法允许这样做。 Here is the javadoc . 这是javadoc This factory is a great example of all three points: 这个工厂是所有三点的一个很好的例子:

  • There are multiple static methods with different names like createEmptyBorder() and createEtchedBorder() . 有多个静态方法具有不同的名称,如createEmptyBorder()createEtchedBorder()
  • These methods will return previously created objects when possible. 这些方法将尽可能返回先前创建的对象。 It's quite frequent that the same border would be used throughout an application. 在整个应用程序中使用相同的边框非常频繁。
  • Border itself is actually an interface, so all objects created through this factory are actually classes which implement this interface. Border本身实际上是一个接口,因此通过此工厂创建的所有对象实际上是实现此接口的类。

The textbook example of your second point is Integer.valueOf(int) (similar for Boolean , Short , Long , Byte ). 第二个点的教科书示例是Integer.valueOf(int) (类似于BooleanShortLongByte )。 For parameter values -128 to 127, this method returns a cached instance instead of creating a new Integer . 对于参数值-128到127,此方法返回缓存的实例,而不是创建新的Integer This makes (auto)boxing/unboxing much more performant for typical values. 这使得(自动)装箱/拆箱对于典型值更加高效。

You can't do that with new Integer() since the JLS requires that new create a new instance every time it is called. 你不能用new Integer()做到这一点,因为JLS要求new在每次调用时都创建一个新实例

My current favorite example of this pattern is Guava 's ImmutableList . 我目前最喜欢的这种模式的例子是GuavaImmutableList Instances of it can only be created by static factories or a builder. 它的实例只能由静态工厂或构建器创建。 Here are some ways that this is advantageous: 以下是一些有利的方法:

  • Since ImmutableList doesn't expose any public or protected constructors, it can be subclassed within the package while not allowing users to subclass it (and potentially break its immutability guarantee). 由于ImmutableList不公开任何publicprotected构造函数,因此它可以在包中进行子类化,同时不允许用户对其进行子类化(并且可能会破坏其不变性保证)。
  • Given that, its factory methods are all able to return specialized subclasses of it without exposing their types. 鉴于此,它的工厂方法都能够返回它的专用子类而不暴露它们的类型。
  • Its ImmutableList.of() factory method returns a singleton instance of EmptyImmutableList . 它的ImmutableList.of()工厂方法返回EmptyImmutableList的单例实例。 This demonstrates how a static factory method doesn't need to create a new instance if it doesn't have to. 这演示了静态工厂方法如何不需要创建新实例。
  • Its ImmutableList.of(E) method returns an instance of SingletonImmutableList which is optimized because it will only ever hold exactly 1 element. 它的ImmutableList.of(E)方法返回一个SingletonImmutableList实例,该实例经过优化,因为它只能保存1个元素。
  • Most of its other factory methods return a RegularImmutableList . 它的大多数其他工厂方法都返回一个RegularImmutableList
  • Its copyOf(Collection) static factory method also does not always need to create a new instance... if the Collection it is given is itself an ImmutableList , it can just return that! 它的copyOf(Collection)静态工厂方法也并不总是需要创建一个新实例......如果给出它的Collection本身就是一个ImmutableList ,它就可以返回它!

Wouldn't Calendar.getInstance() be a good exmaple? Calendar.getInstance()不是一个很好的例子吗? It creates depending on the locale a BuddhistCalendar, JapaneseImperialCalendar or by default a GregorianCalendar. 它根据语言环境创建BuddhistCalendar,JapaneseImperialCalendar或默认为GregorianCalendar。

Here is one I had to do a while back. 这是我不得不做的一件事。 At a job interview, I was asked to program a deck of cards where they can be shuffled. 在一次求职面试中,我被要求编制一副卡片,在那里可以洗牌。 Really simple problem. 真的很简单的问题。 I created: 我建立:

Card:
  suit
  rank

Deck:
  card[]

I think what was the distinguishing factor is that there can only 52 cards at all times. 我认为区别的因素是,任何时候都只能有52张牌。 So I made the constructor for Card() private and instead create static factory valueOf(suit, rank) This allowed me to cache the 52 cards and make the immutable. 所以我将Card()的构造函数设为私有,而是创建静态工厂valueOf(suit,rank)这允许我缓存52张卡并使其成为不可变的。 It taught many important basic lessons in that books. 它教了很多重要的基础课程。

  1. immutable 一成不变
  2. control creation of object 控制对象的创建
  3. static methods 静态方法
  4. possibly subclassing and return a card from another source. 可能是子类并从另一个来源返回一张卡片。 ( I didn't do this) (我没有这样做)

This is similar to Boolean and Byte, except I used a common homework example to show why its important to control the instances. 这类似于布尔和字节,除了我使用一个常见的作业示例来说明控制实例的重要性。 I also created a helper function for deck called newDeck() because I wanted to show an instance where the constructor might not need to be private but it would still be nice to have a helper static factory. 我还为deck创建了一个名为newDeck()的辅助函数,因为我想显示一个实例,其中构造函数可能不需要是私有的,但是拥有一个帮助器静态工厂仍然很好。

I hope this helps! 我希望这有帮助!

The simple case. 这个简单的案例。 Suppose you have a class which operates some sort of printer, but it doesn't care if it is epson, canon or something else. 假设你有一个操作某种打印机的类,但它不关心它是epson,canon还是其他东西。 So, you just create an Interface Printer , create some implementations of it and create a class which has only one method: createPrinter. 因此,您只需创建一个接口Printer ,创建它的一些实现并创建一个只有一个方法的类:createPrinter。

So, the code will be simple: 所以,代码很简单:

   public interface Printer {
       print();
    }

    class CanonPrinter implements Printer {
       print() {
    // ...
       }
    }


    public PrinterFactory {

    Printer createPrinter() {
   if (... ) {
      return new CanonPrinter();
   } else {
      return new EpsonPrinter();
   }
}
}

client code: 客户代码:

Printer printer = PrinterFactory.createPrinter();
printer.print();

Here you abstract you clinet code from any details of what printers you can operate with or how they manage printing. 在这里,您可以从您可以操作的打印机的任何细节或管理打印的方式中抽象出clinet代码。 It's PrinterFactory who cares what printer to choose if one for example malfunctions. 它是PrinterFactory,如果一个例如出现故障,他会关心选择什么打印机。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM