简体   繁体   English

不可变类/对象,私有构造函数,工厂方法

[英]Immutable class/object, private Constructor, factory method

Having already read how to make a class Immutable by following steps 已经阅读了如何通过以下步骤使类成为不可变的

  1. Don't provide "setter" methods — methods that modify fields or objects referred to by fields. 不要提供“setter”方法 - 修改字段引用的字段或对象的方法。
  2. Make all fields final and private. 使所有字段成为最终和私有。
  3. Don't allow subclasses to override methods. 不允许子类重写方法。 The simplest way to do this is to declare the class as final. 最简单的方法是将类声明为final。 A more sophisticated approach is to make the constructor private and construct instances in factory methods. 更复杂的方法是使构造函数私有并在工厂方法中构造实例。
  4. If the instance fields include references to mutable objects, don't allow those objects to be changed: 如果实例字段包含对可变对象的引用,则不允许更改这些对象:
    a. 一个。 Don't provide methods that modify the mutable objects. 不要提供修改可变对象的方法。
    b. Don't share references to the mutable objects. 不要共享对可变对象的引用。 Never store references to external, mutable objects passed to the constructor; 永远不要存储对传递给构造函数的外部可变对象的引用; if necessary, create copies, and store references to the copies. 如有必要,创建副本并存储对副本的引用。 Similarly, create copies of your internal mutable objects when necessary to avoid returning the originals in your methods. 同样,必要时创建内部可变对象的副本,以避免在方法中返回原始对象。

AM not sure I clearly understand the utility of private constructor and factory method in the context of immutability. AM不确定我是否清楚地了解私有构造函数和工厂方法在不变性方面的效用。 If I make class final, basically am closing all paths of any other class extending it. 如果我让类最终,基本上是关闭任何其他类扩展它的所有路径。 How is the stated a more sophisticated approach 如何陈述更复杂的方法

I have seen private constructor,factory method in Singleton pattern which makes sense. 我在Singleton模式中看到了私有构造函数,工厂方法,这是有道理的。 But when we talk of object immutability, are we also restricting object construction/instantiation when we mention private constructor and static factory methods?? 但是当我们谈论对象不变性时,当我们提到私有构造函数和静态工厂方法时,我们是否也限制了对象构造/实例化?

Firstly, there are several reasons why immutable class generally should not be overriden, you can find them here . 首先,有几个原因通常不应该覆盖不可变类,你可以在这里找到它们。

That said, making a constructor private is just one way to prevent class from being overriden. 也就是说,将构造函数设为私有只是阻止类被覆盖的一种方法。 Why? 为什么? Because in sub-class, every constructor (implicitly) calls super() , a default constructor of base class. 因为在子类中,每个构造函数(隐式地)都调用super() ,它是基类的默认构造函数。 But if you make this constructor private, sub-class cannot call it and thus cannot override the base class. 但是如果你将这个构造函数设为私有,则子类不能调用它,因此不能覆盖基类。 This approach is very suitable when you want to control the total number of instances of particular class, for example in case of singletons. 当您想要控制特定类的实例总数时,此方法非常适合,例如在单例的情况下。

I think the big issue here is future refactoring. 我认为这里的重大问题是未来的重构。 Suppose, in a later version, you find it would make something much simpler if you could split out some new special case of MyClass into a subclass, MySpecialClass. 假设,在更高版本中,如果您可以将MyClass的一些新特殊情况拆分为子类MySpecialClass,则会发现它会更简单。

If MyClass were a mutable class with a public constructor, you could just do it and tell users of the new features to create a new MySpecialClass. 如果MyClass是一个带有公共构造函数的可变类,您可以这样做并告诉用户新功能以创建一个新的MySpecialClass。 Existing uses are not affected. 现有用途不受影响。

If MyClass has a private constructor and a factory method, there is no problem. 如果MyClass有私有构造函数和工厂方法,则没有问题。 You declare MySpecialClass nested in MyClass, also with a private constructor. 您声明MySpecialClass嵌套在MyClass中,也使用私有构造函数。 Add and/or modify the factory methods to choose which to create, but make sure existing calls go on working compatibly. 添加和/或修改工厂方法以选择要创建的方法,但要确保现有的调用继续兼容。

What would you do if MyClass were immutable, and final, but had a public constructor? 如果MyClass是不可变的,那么你会做什么,最后,但是有一个公共构造函数?

Yeah, you are right. 是的,你是对的。 It does not make any sense to make constructor private. 将构造函数设为私有没有任何意义。 By doing this, we are restricting the instance creation, which is not a desired scenario for immutability. 通过这样做,我们限制了实例创建,这不是不可变的期望场景。

In example mentioned in sun site does not make constructor private http://docs.oracle.com/javase/tutorial/essential/concurrency/syncrgb.html 在sun网站中提到的示例中没有使构造函数私有http://docs.oracle.com/javase/tutorial/essential/concurrency/syncrgb.html

IMMUTABILITY - Very helpful for concurrency as it avoids creation of various invariant that are possible in threading environment. IMMUTABILITY - 非常有助于并发,因为它避免了在线程环境中创建各种不变量

FACTORY METHODS - Just a naming convention, as they are more verbose to read and easy to understand from their custom name. 工厂方法 -只是一个命名规则,因为它们更详细阅读和容易从他们的自定义名称理解。 For example: copyOf() method would make more sense than creating a copy constructor. 例如: copyOf()方法比创建复制构造函数更有意义。 As said by Joshua Bloch in Effective Java 正如Joshua Bloch在Effective Java中所说的那样

PRIVATE CONSTRUCTORS - They have their own uses in patterns like Singleton, but have their own limitations. 私有构造函数 - 它们在像Singleton这样的模式中有自己的用途,但也有其自身的局限性。

After thoroughly reading the below point 仔细阅读以下几点

Dont allow subclass to over ride methods. 不要允许子类过载方法。 The simplest way to do this is to declare the class final. 最简单的方法是声明类final。 A more sophisticated approach is to make constructor private and construct instances in factory method. 更复杂的方法是使构造函数私有并在工厂方法中构造实例。

I think the point here is not 我认为这里的重点不是

Making class final and private constructor. 使类最终和私有构造函数。

The point is 重点是

Either you make your class final or have a private constructor. 要么让你的班级成为最终的,要么拥有私人构造函数。

Hope it helps!! 希望能帮助到你!!

source 资源

Some of my own findings from Effective Java Item 15, pasting relevant statements from the same 我自己的一些发现来自Effective Java Item 15,粘贴了相同的相关陈述

"Recall that to guarantee immutability, a class must not permit itself to be subclassed. Typically this is done by making the class final, but there is another, more flexible way to do it. The alternative to making an immutable class final is to make all of its constructors private or package-private, and to add public static factories in place of the public constructors (Item 1). “回想一下,为了保证不变性,一个类不能允许自己被子类化。通常这是通过使类最终完成,但还有另一种更灵活的方法来实现它。使不可变类最终的替代方法是制作它的所有构造函数私有或包私有,并添加公共静态工厂来代替公共构造函数(第1项)。

While this approach is not commonly used, it is often the best alternative. 虽然这种方法并不常用,但它通常是最好的选择。 It is the most flexible because it allows the use of multiple package-private implementation classes. 它是最灵活的,因为它允许使用多个包私有实现类。 To its clients that reside outside its package, the immutable class is effectively final because it is impossible to extend a class that comes from another package and that lacks a public or protected constructor. 对于位于其包之外的客户端,不可变类实际上是最终的,因为不可能扩展来自另一个包并且缺少公共或受保护构造函数的类。 Besides allowing the flexibility of multiple implementation classes, this approach makes it possible to tune the performance of the class in subsequent releases by improving the objectcaching capabilities of the static factories. 除了允许多个实现类的灵活性之外,这种方法还可以通过改进静态工厂的对象缓存功能来调整后续版本中类的性能。

"

static factory vs constructor advantages are then discussed 然后讨论静态工厂与构造函数的优点

The idea behind the private constructor is that you want to hide the immutable implementation of the class data whilst allowing construction of a new instance with different data of the same internal type. 私有构造函数背后的想法是,您希望隐藏类数据的不可变实现,同时允许构建具有相同内部类型的不同数据的新实例。

For example 例如

public class Temperature
{
    private readonly double temperatureInCelsius;

    public Temperature(string temperatureInCelsius)
    {
         this.temperatureInCelsius = System.Convert.ToDouble(temperatureInCelsius);
    }
    private Temperature(double temperatureInCelsius)
    {
         this.temperatureInCelsius = temperatureInCelsius;
    }

    public Temperature AddCelsius(string temperatureToAddInCelsius)
    {
         return new Temperature(System.Convert.ToDouble(temperatureToAddInCelsius) + temperatureInCelsius);
    }
    public void PrintCelsius(Display display)
    {
        display.Print(temperatureInCelsius);
    }
    public void PrintFarenheit(Display display)
    // ... etc
}

Ignoring the semi stupidity of the example, if your requirements are that the class can be constructed from a string representing the temperature. 忽略示例的半愚蠢,如果您的要求是可以从表示温度的字符串构造类。 The way it actually stores the temperature is subject to change and is an implementation detail. 它实际存储温度的方式可能会发生变化,并且是一个实现细节。 This class can be changed to use floats, strings, doubles, ints etc. This method maintains immutability whilst allowing flexibility on implementation. 可以将此类更改为使用浮点数,字符串,双精度数,整数等。此方法保持不变性,同时允许实现的灵活性。 Obviously this becomes much more powerful when you are wrapping more complex objects such as collections, dictionaries etc. 显然,当您包装更复杂的对象(如集合,词典等)时,这会变得更加强大。

That is because with private constructor we can not make a subclass of it, and thus restricting all paths of any other class extending it. 这是因为使用私有构造函数我们不能创建它的子类,因此限制任何其他类的扩展它的所有路径。 It is sophisticated because it has its own limitations/complications like in singleton pattern. 它很复杂,因为它有自己的限制/复杂性,如单身模式。

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

相关问题 带有私有构造函数和scala工厂的类? - Class with private constructor and factory in scala? 如果Java中的类具有私有的mutator方法,它是否可以是不可变的? - Can a class in Java be immutable if it has a private mutator method? 带有私有不可变对象的同步块和同步方法的区别 - Synchronized block with private immutable object and synchronize method difference SonarQube违规:内部类私有构造函数上未使用的私有方法 - SonarQube violation: Unused private method on inner class private constructor 工厂方法构造Java对象:属性vs构造函数(通过方法) - Java object construction by factory method: attribute vs constructor (via method) 用工厂方法替换构造函数 - Replace constructor with factory method 没有默认构造函数和私有方法的Abstract类的测试类? - Test class for Abstract class with no default constructor and private method? 类的构造方法,其上级只能通过工厂方法制成 - Constructor for a class whose super should only be made via factory method Java - 私有内部类的对象,作为外部类构造函数的参数 - Java - object of a private inner class being as an argument to an outer class' constructor Java反射-调用具有私有构造函数的泛型类的静态方法 - Java reflection - Call a static method of a generic class that has private constructor
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM