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