工厂用Java生产的只读对象 在以前的C++代码中,我在创建一个工厂时使用了朋友类,可以输出“只读”对象,这意味着当对象在整个代码中被消耗时,没有可能会被无意地改变/损坏。

工厂用Java生产的只读对象 在以前的C++代码中,我在创建一个工厂时使用了朋友类,可以输出“只读”对象,这意味着当对象在整个代码中被消耗时,没有可能会被无意地改变/损坏。,java,Java,在Java中是否有类似的方法来实现这一点,或者我是否过于保守?使用final关键字。该关键字可以将类/方法标记为不可扩展,并将字段/变量标记为不可变 您将使用private构造函数隐藏对象的默认构造函数,并强制参数化构造函数初始化所有必需的最终字段 你唯一的问题是工厂有点多余。因为对象的所有字段都是最终字段,所以在对象构建时必须使用所有工厂方法 例如: public final class DataObject { protected final String name;

在Java中是否有类似的方法来实现这一点,或者我是否过于保守?

使用
final
关键字。该关键字可以将类/方法标记为不可扩展,并将字段/变量标记为不可变

您将使用
private
构造函数隐藏对象的默认构造函数,并强制参数化构造函数初始化所有必需的最终字段

你唯一的问题是工厂有点多余。因为对象的所有字段都是最终字段,所以在对象构建时必须使用所有工厂方法

例如:

 public final class DataObject
 {
     protected final String name;
     protected final String payload;

     private DataObject()
     {

     }

     public DataObject(final String name, final String payload)
     {
         this.name = name;
         this.payload = payload;
     }
}

// Using the factory
DataObject factory = new Factory().setName("Name").setPayload("Payload").build();

// As opposed to
DataObject dao = new DataObject("Name", "Payload");

// ==> Factory becomes redundant, only adding extra code
public class Factory 
{
    private String name;
    private String payload;

    public Factory setName(final String name)
    {
        this.name = name;
    }

    public Factory setPayload(final String payload)
    {
        this.payload = payload;
    }

    public DataObject build()
    {
        DataObject newObj = new DataObject();
        newObj.setName( this.name );
        newObj.setPayload( this.payload );
        return newObj;
    }

    public class DataObject
    {
        // fields and setters, ALL PRIVATE
    }
}

不带
最终版的解决方案

恐怕你将不得不忘记C++的不可变机制。如果您有巨大的数据对象(即有许多setter),那么工厂模式从来都不是一个坏的选择,但是您无法真正避免构造对象的可变性。您可以做的是将数据对象设置为工厂的内部类,并将setter设置为私有。这样,只有工厂才能访问设定器。这将是您的最佳方法(即模拟不变性)

例如:

 public final class DataObject
 {
     protected final String name;
     protected final String payload;

     private DataObject()
     {

     }

     public DataObject(final String name, final String payload)
     {
         this.name = name;
         this.payload = payload;
     }
}

// Using the factory
DataObject factory = new Factory().setName("Name").setPayload("Payload").build();

// As opposed to
DataObject dao = new DataObject("Name", "Payload");

// ==> Factory becomes redundant, only adding extra code
public class Factory 
{
    private String name;
    private String payload;

    public Factory setName(final String name)
    {
        this.name = name;
    }

    public Factory setPayload(final String payload)
    {
        this.payload = payload;
    }

    public DataObject build()
    {
        DataObject newObj = new DataObject();
        newObj.setName( this.name );
        newObj.setPayload( this.payload );
        return newObj;
    }

    public class DataObject
    {
        // fields and setters, ALL PRIVATE
    }
}

Java中没有直接等同于友元的类。但是请看一看。

您可以将对象类和工厂放在同一个包中,并将可变方法包范围化(这是Java中的默认可见性,只是不要将方法声明为
public
private
protected
),或者使类真正不可变,并在构造函数中完成所有工作。如果发现构造函数中有太多的参数,很难理解,请考虑.< /p>

如果您的对象实现了接口,并且工厂返回接口类型而不是具体类型(更好)然后,您可以使用java.lang.reflect.Proxy在运行时创建动态代理,以拦截对目标对象的所有方法调用。与下面的代码示例一样,类创建一个Foo实例(每次调用其createFoo方法时)但不直接返回实例,而是返回一个动态代理,该代理实现与Foo相同的接口,并且动态代理截获并将所有方法调用委托给Foo实例。当您没有类代码时,此机制有助于控制对类的访问

    public class FooFactory {


    public static IF createFoo() {

        //Create Foo instance
        Foo target = new Foo(); // Implements interface IF

        //Create a dynamic proxy that intercepts method calls to the Foo instance
        IF fooProxy = (IF) Proxy.newProxyInstance(IF.class.getClassLoader(),
                new Class[] { IF.class }, new IFInvocationHandler(target));

        return fooProxy;

    }

}

class IFInvocationHandler implements InvocationHandler {

    private Foo foo;

    IFInvocationHandler(Foo foo) {
        this.foo = foo;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {

        if (method.getName().equals("setMethod")) {
            // Block call
            throw new IllegalAccessException();
        } else {
            // Allow call
            method.invoke(proxy, args);
        }
        return null;
    }
}

class Foo implements IF {
    public void setMethod() {
    } // method that is not allowed to call

    public void getMethod() {
    }

}

interface IF {
    void setMethod(); // method that is not allowed to call

    void getMethod(); // method that is allowed to call
}

java中C++好友类最接近的是包私用访问。

SomeObject.java:

package somewhere.someobjandfriends;

public class SomeObject {
    Object aField;   // field and constructor
    SomeObject() {}  // are package-only access

    public void aMethod() {
        System.out.println(this);
    }
}
package somewhere.someobjandfriends;

public class SomeObjFactory {
    public SomeObject newHelloWorld() {
        return new SomeObject() {
            {
                aField = "hello world!";
            }
            @Override
            public String toString() {
                return aField.toString();
            }
        };
    }
}
SomeObjFactory.java:

package somewhere.someobjandfriends;

public class SomeObject {
    Object aField;   // field and constructor
    SomeObject() {}  // are package-only access

    public void aMethod() {
        System.out.println(this);
    }
}
package somewhere.someobjandfriends;

public class SomeObjFactory {
    public SomeObject newHelloWorld() {
        return new SomeObject() {
            {
                aField = "hello world!";
            }
            @Override
            public String toString() {
                return aField.toString();
            }
        };
    }
}

包外的任何地方都可以看到
SomeObject
aMethod
,但只能通过工厂创建新实例。

您好,感谢您的回答,我的设计可能很差,但我目前调用方法“构造”对象。我发现这比在构造器中完成这一切更干净、更直接,所以我认为在这里使用final不会起作用,因为只有正确理解final关键字,我才能在构造器中进行编辑。我正在构建一个层次结构,我在一个构造函数中发现它很难做到。@ Cube恐怕你必须忘记C++的不可变机制。如果您有巨大的数据对象(即有许多setter),那么工厂模式从来都不是一个坏的选择,但是您无法真正避免构造对象的可变性。您可以做的是将数据对象设置为工厂的内部类,并将setter设置为私有。这样,只有工厂才能访问设定器。这将是您的最佳方法(即模拟不变性)。