Mal*_*lax 96 java oop scala immutability
我有一些大的(超过3个字段)对象,它们可以而且应该是不可变的.每次遇到这种情况时,我倾向于使用长参数列表创建构造函数可恶.它感觉不对,难以使用,可读性受损.
如果字段是某种类似列表的集合类型则更糟糕.一个简单的方法addSibling(S s)可以简化对象的创建,但会使对象变得可变.
在这种情况下你们有什么用?我在使用Scala和Java,但我认为只要语言是面向对象的,问题就是语言不可知.
我能想到的解决方案:
感谢您的输入!
Syn*_*r0r 75
那么,你想要一个创建后更容易阅读和不可变的对象?
我认为一个流畅的界面正确完成会帮助你.
它看起来像这样(纯粹的例子):
final Foo immutable = FooFactory.create()
.whereRangeConstraintsAre(100,300)
.withColor(Color.BLUE)
.withArea(234)
.withInterspacing(12)
.build();
Run Code Online (Sandbox Code Playgroud)
我用粗体写了"CORRECTLY DONE",因为大多数Java程序员错误地使用流畅的接口并用构建对象所需的方法污染他们的对象,这当然是完全错误的.
诀窍是只有build()方法实际上创建了一个Foo(因此你Foo可以是不可变的).
FooFactory.create(),其中XXX(...)和withXXX(..)都创建"其他东西".
其他东西可能是一个FooFactory,这是一种方法来做到这一点....
You FooFactory看起来像这样:
// Notice the private FooFactory constructor
private FooFactory() {
}
public static FooFactory create() {
return new FooFactory();
}
public FooFactory withColor( final Color col ) {
this.color = color;
return this;
}
public Foo build() {
return new FooImpl( color, and, all, the, other, parameters, go, here );
}
Run Code Online (Sandbox Code Playgroud)
Mar*_*sky 60
在Scala 2.8中,您可以使用命名和默认参数以及copy案例类上的方法.这是一些示例代码:
case class Person(name: String, age: Int, children: List[Person] = List()) {
def addChild(p: Person) = copy(children = p :: this.children)
}
val parent = Person(name = "Bob", age = 55)
.addChild(Person("Lisa", 23))
.addChild(Person("Peter", 16))
Run Code Online (Sandbox Code Playgroud)
Dan*_*ral 20
好吧,在Scala 2.8上考虑一下:
case class Person(name: String,
married: Boolean = false,
espouse: Option[String] = None,
children: Set[String] = Set.empty) {
def marriedTo(whom: String) = this.copy(married = true, espouse = Some(whom))
def addChild(whom: String) = this.copy(children = children + whom)
}
scala> Person("Joseph").marriedTo("Mary").addChild("Jesus")
res1: Person = Person(Joseph,true,Some(Mary),Set(Jesus))
Run Code Online (Sandbox Code Playgroud)
当然,这确实有一些问题.例如,尝试制作espouse和Option[Person],然后要结婚了对方两个人.如果不诉诸于private var和/或private构造函数以及工厂,我无法想出解决这个问题的方法.
Lit*_*les 11
以下是几个选项:
使实现本身可变,但将它公开的接口分离为可变和不可变.这取自Swing库设计.
public interface Foo {
X getX();
Y getY();
}
public interface MutableFoo extends Foo {
void setX(X x);
void setY(Y y);
}
public class FooImpl implements MutableFoo {...}
public SomeClassThatUsesFoo {
public Foo makeFoo(...) {
MutableFoo ret = new MutableFoo...
ret.setX(...);
ret.setY(...);
return ret; // As Foo, not MutableFoo
}
}
Run Code Online (Sandbox Code Playgroud)
如果您的应用程序包含大量但预定义的不可变对象集(例如,配置对象),则可以考虑使用Spring框架.
考虑四种可能性:
new Immutable(one, fish, two, fish, red, fish, blue, fish); /*1 */
params = new ImmutableParameters(); /*2 */
params.setType("fowl");
new Immutable(params);
factory = new ImmutableFactory(); /*3 */
factory.setType("fish");
factory.getInstance();
Immutable boringImmutable = new Immutable(); /* 4 */
Immutable lessBoring = boringImmutable.setType("vegetable");
Run Code Online (Sandbox Code Playgroud)
对我来说,2,3和4中的每一个都适应不同的情况.第一个是用心的去爱,由OP提到的原因,一般是遭受了一些野外,需要一些重构设计的一种症状.
我所列的(2)在"工厂"背后没有状态时是好的,而(3)是有状态时的选择设计.当我不想担心线程和同步时,我发现自己使用(2)而不是(3),并且我不需要担心在许多对象的生产中分摊一些昂贵的设置.另一方面,当实际工作进入工厂建设时(从SPI设置,读取配置文件等),会调出(3).
最后,别人的回答提到了选项(4),其中你有很多小的不可变对象,而最好的模式是从旧的获取新闻.
请注意,我不是"模式粉丝俱乐部"的成员 - 当然,有些事情值得效仿,但在我看来,一旦人们给他们起名字和有趣的帽子,他们就会有一种无益的生活.
您还可以使不可变对象公开看起来像mutator的方法(如addSibling),但让它们返回一个新实例.这就是不可变的Scala集合所做的.
缺点是您可能会创建多于必要的实例.它也只适用于当不存在中间有效配置(如没有兄弟姐妹这是确定在大多数情况下,一些节点),除非你不想处理部分建成的对象.
例如,没有目的地的图形边缘不是有效的图形边缘.