【问题标题】:Changing mutable class into immutable将可变类更改为不可变类
【发布时间】:2015-08-03 20:42:52
【问题描述】:

我正面临一个需要帮助的架构决策。

我正在创建一个可供多个客户使用的库。在这个库中,我有一个名为LibClass 的类,它有一个名为aProperty 的读写属性,还有一个名为LibManager 的类,它包含对Libclass 实例的引用。 LibManager 负责更新LibClass 属性。

客户端可以通过LibManager上的方法获取LibClass实例,我们称之为getLibClassInstanceMethod

我不希望我的客户能够在LibClass 中更改aProperty,因为这意味着客户可以更改我的库模型。我只希望LibManager 可以更改aProperty 的访问权限。

我一直在考虑几种解决方案:

选项 1

getLibClassInstanceMethod 内返回对象的深层副本。

优点: 我始终确信只有库才能完全访问模型。

缺点: 内存消耗 - 每次我想获取对象时,我都需要克隆它。

选项 2

使LibClass 不可变;每次我想更改类属性时,我都需要创建一个新类并在指定的初始化程序(构造函数)中传递新值并销毁旧对象。

优点: 我让类变得不可变,这正是我想要的

缺点: 当类变大时,总是因为一个属性改变而重新创建类有点奇怪。

选项 3

创建某种可变/不可变对,例如 NSString/NSMutableString。

优点: 不确定

缺点: 每个类都需要两个对应的类,使类的数量增加一倍。

我真的不知道该走哪条路。你会怎么做?

谢谢

【问题讨论】:

  • 我喜欢 3 选项,但您也可以使 LibClass 不可变并创建单独的类来修改它,如 LibEditor。第一次你总是可以重新创建你想要编辑的 LibClass(在 LibEditor 中实现),但之后你可以将实现更改为更高效
  • 只是不要暴露设置器。即,因为您正在使用 objC,所以您可以完全控制您在标题中声明的内容。因此,只需将 setter 保持私有,并仅公开 getter,以便这些属性对客户端似乎是只读的
  • Jef,LibManager 需要访问权限,因此我无法将其设为只读。
  • 我没有说让它只读,我说让它看起来对客户只读。制作一个私有标头/扩展名/类别,公开您的 libManager 的设置器;)

标签: ios objective-c oop design-patterns shared-libraries


【解决方案1】:

如 Jef 所说,一种方法就是这样做。

在接口里面的LibClass.h中:

@property (strong, readonly) id aProperty;

在新文件 LibClassPrivate.h 中:

@interface LibClass ()
@property (strong, readwrite) id aPropertyWritable;
@end

在 LibClass.m 中:

@implementation LibClass{
    id _aProperty;
}

- (id) aProperty{
    return [_aProperty copy];
}

- (void) setAPropertyWritable: (id) aPropertyWritable {
    _aProperty = aPropertyWritable;
}
- (id) aPropertyWritable{
    return _aProperty;
}
@end

基本上,我们有两个属性。两者都由一个实例变量支持。在我们的公共标头中显示的那个只能返回 ivar 的副本。在我们的私有标头中显示的那个可以读取和写入 ivar。任何需要能够使用读写访问器的类都可以将私有头 #import 放入它们的 .m 文件中。

只要确保 _aProperty 的任何类型的对象都实现了 copyWithZone:。

顺便说一句,苹果也提到了这种方法。

如果您打算将“私有”方法或属性提供给 选择其他类,例如框架内的相关类,您 可以在单独的头文件中声明类扩展并导入 它在需要它的源文件中。有两个并不少见 类的头文件,例如 XYZPerson.h 和 XYZPersonPrivate.h。当你发布框架时,你只发布 公共 XYZPerson.h 头文件。

【讨论】:

  • 从你写的 LibManager 不能改变 aPropertyWritable。
  • @kernix 也许我忘记了什么?但我实现了这一点并对其进行了测试。在 LibManager 中,我可以使用 .aPropertyWritable,它可以很好地设置和获取 .aProperty,而尝试从 LibManager 外部设置 .aProperty 给了我一个编译器错误,并且从外部获取它返回了一个副本。
  • 你的意思是 LibClass 不能改吗?因为那是真的。我会编辑我的帖子。
  • Metabble 感谢您的回复!我希望 LibManager 持有对 LibClass 的引用,而不是直接持有对属性的引用。
  • @kernix 我对其进行了编辑以使其更清晰。我无法上传到 GitHub,但制作测试项目应该很容易。只需创建一个新项目,创建一个类。使用已编辑答案中的代码添加属性。请注意,导入私有标头的任何内容都可以使用 readwrite 属性,而仅导入普通标头的任何内容都不能。显然,您用于属性的任何类型的对象都需要是可复制的。
【解决方案2】:

那……呢?

.h 文件

@property (strong, nonatomic, readonly) id lib;

.m 文件

@interface LibManager ()
@property (strong, nonatomic, readwrite) id lib;
@end

@implementation LibManager
@synthesize lib = _lib;
// ...

- (id)lib
{
    return [_lib copy];
}

- (id)_internal_get_mutable_lib
{
    return _lib;
}
@end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-20
    • 2016-12-11
    • 2014-08-07
    • 1970-01-01
    • 1970-01-01
    • 2011-12-24
    相关资源
    最近更新 更多