面向对象的编程:getter / setter或逻辑名


12

我目前正在考虑要编写的类的接口。此类包含字符的样式,例如,字符是否为粗体,斜体,带下划线等。我已经辩论了两天,是否应该将getter / setter或逻辑名用于将值更改为这些样式。尽管我倾向于使用逻辑名称,但这确实意味着编写的代码效率不高,逻辑也不如逻辑。让我举一个例子。

我有一类CharacterStyles具有成员变量bolditalicunderline(和其他一些人,但我会留下来,以保持它的简单)。允许程序其他部分访问这些变量的最简单方法是编写getter / setter方法,以便您可以执行styles.setBold(true)styles.setItalic(false)

但是我不喜欢这样。不仅是因为很多人说吸气剂/装料剂破坏了封装(真的那么糟糕吗?),而且主要是因为它对我而言似乎不合逻辑。我希望通过一种方法styles.format("bold", true)或类似方法来设置角色的样式,但不能通过所有这些方法来设置样式。

不过有一个问题。由于您无法通过C ++中的字符串内容访问对象成员变量,因此我要么必须为所有样式编写一个大的if语句/开关容器,要么必须将样式存储在关联数组中(地图)。

我不知道什么是最好的方法。我想我应该写吸气剂/设定器,下一刻我倾向于另一种方式。我的问题是:你会怎么做?为什么要这么做?


除了将三个布尔值捆绑在一起,CharacterStyles类实际上是否做其他任何事情?它如何被消耗?
Mark Canlas 2012年

是的,因为CharacterStyles应该能够从其他CharacterStyles继承。这意味着如果我的CharacterStyles bold设置为true,而其他变量未定义,则其他变量的getter方法应返回父样式的值(存储在另一个属性中),而该bold属性的getter 应该返回true。还有其他一些东西,例如名称及其在界面中的显示方式。
青蛙

您可以使用枚举来定义各种样式选项,然后使用switch语句。顺便说一句,您如何处理未定义?
蒂安娜(Tyanna)2012年

@Tyanna:的确,我也考虑过使用枚举,但这只是一个小细节。我打算将未定义的值设置为NULL。那不是最好的方法吗?
青蛙

Answers:


6

是的,getter / setter确实破坏了封装-它们基本上只是直接访问基础字段之间的额外一层。您最好直接访问它。

现在,如果您希望使用更复杂的方法访问该字段,那是有效的,但是除了公开该字段之外,您还需要考虑该类应该提供哪些方法。即。而不是使用通过属性公开的具有Money值的Bank类,您需要考虑Bank对象应提供的访问类型(增加资金,提取资金,获取余额)并实施这些访问。Money变量上的属性在语法上与直接公开Money变量仅在语法上有所不同。

DrDobbs有一篇文章说得更多。

对于您的问题,我将使用2种方法setStyle和clearStyle(或其他方法)来列举可能的样式。然后,这些方法中的switch语句会将相关值应用于适当的类变量。这样一来,你可以的风格内部表示更改为别的,如果您稍后决定将它们存储为一个字符串(用于在HTML中使用为例) -这会需要你的类的所有用户都将被改变,如果你使用过获取/设置属性。

如果要获取任意值,或者仍然有一个很大的if-then语句(如果有几个),或者使用std :: mem_fun(或std ::函数),因此“粗体”将以sts :: mem_fun的值存储在映射键中,该方法将变量粗体设置为true(如果字符串与成员变量名称相同,那么您也可以使用该字符串化宏观减少代码,你需要写的金额)


很好的答案!特别是有关将数据存储为HTML的部分使我震惊,这确实是走这条路的好理由。因此,您建议将不同的样式存储在枚举中,然后设置类似的样式styles.setStyle(BOLD, true)?那是对的吗?
青蛙

是的,只有我有2种方法-setStyle(BOLD)和clearstyle(BOLD)。忘记第二个参数,我只是喜欢这样,然后可以重载clearStyle以不带任何参数来清除所有样式标志。
gbjbaanb 2012年

那是行不通的,因为某些类型(如font-size)需要一个参数。但是仍然感谢您的回答!
青蛙2012年

我一直在尝试实现这一点,但是我没有考虑一个问题:styles.getStyle(BOLD)当您不仅具有布尔类型的成员变量,而且具有整数和字符串类型的成员变量(例如:)时,如何实现styles.getStyle(FONTSIZE)。既然您不能重载返回类型,那么如何编程呢?我知道您可以使用void指针,但这听起来对我来说真的很糟糕。您对此有任何提示吗?
青蛙

您可以返回联合,结构或新标准,也可以按返回类型进行重载。就是说,您是否要尝试实现一种设置样式的方法,其中样式是一个标志,一个字体家族和一个大小?在这种情况下,也许您试图将抽象强制得太多。
gbjbaanb 2012年

11

您可能没有考虑过的一个想法是装饰器模式。而不是在对象中设置标志,然后将这些标志应用于正在编写的任何内容,而是在Decorators中包装完成编写的类,该类又将应用样式。

调用代码不需要知道您在文本周围放了多少个包装,您只需在外部对象上调用一个方法并调用堆栈即可。

对于伪代码示例:

class TextWriter : TextDrawingInterface {
    public:
        void WriteString(string x) {
            // write some text somewhere somehow
        }
}

class BoldDecorator : TextDrawingInterface {
    public:
        void WriteString(string x) {
            // bold application on
            m_textWriter.WriteString(x);
            // bold application off
        }

        ctor (TextDrawingInterface textWriter) {
            m_textWriter = textWriter;
        }

    private:
        TextWriter m_TextWriter;
}

依此类推,适用于每种装饰风格。在最简单的用法中,您可以说

TextDrawingInterface GetDecoratedTextWriter() {
    return new BoldDecorator(new ItalicDecorator(new TextWriter()));
}

而且调用此方法的代码不需要知道其接收的详细信息。只要它可以通过WriteString方法绘制文本即可。


嗯,明天我将以崭新的心态看一下这个问题,然后会尽快回复您。谢谢你的回答。
青蛙2012年

我非常喜欢Decorator模式。这种模式类似于HTML(其核心操作是用标签将输入字符串括起来),这一事实证明了这种方法可以满足您的所有界面用户需求。要记住的一件事是,良好且易于使用的接口可能具有技术上复杂的基础实现。例如,如果你实际上是实现文本呈现自己,你可能会发现,TextWriter需要通话双方BoldDecoratorItalicDecorator(双向),以完成这项工作。
rwong 2012年

虽然这是一个不错的答案,但它不会重新介绍操作员的问题吗?“大胆的应用程序”->这将如何进行?使用像SetBold()这样的setters / getters?这正是操作人员的问题。
stijn 2012年

1
@stijn:不是。有许多避免这种情况的方法。例如,可以使用toggleStyle方法(枚举参数)将其包装在构建器中,该方法可以从数组中添加和删除装饰器,仅当调用BuildDecoratedTextWriter时才装饰最后一个项目。或者您可以按照rwong的建议进行操作,并使基类复杂化。视情况而定,OP对总体规格不够具体,无法猜测哪个对他最合适。不过,他似乎很聪明,可以一旦找到模式就可以弄清楚。
pdr

1
我一直认为装饰图案代表装饰的顺序。考虑所示的示例代码;如何删除ItalicDecorator?不过,我认为类似Decorator的方法仍然可行。并非只有粗体,斜体和下划线这三种样式。有薄型,半粗体型,浓缩型,黑色,宽型,带斜体的斜体,小号等。您可能需要一种将任意大的样式应用于角色的方法。
巴里·布朗

0

我倾向于第二种解决方案。它看起来更加优雅和灵活。尽管很难想象除了粗体,斜体和下划线(上划线?)以外的其他类型,但是使用成员变量添加新类型将很困难。

我在最新的项目之一中使用了这种方法。我有一个可以具有多个布尔属性的类。属性的数量和名称可能会随时间变化。我将它们存储在字典中。如果不存在属性,则假定其值为“ false”。我还必须存储可用属性名称的列表,但这是另一回事了。


1
除了这些类型之外,我还将在以后添加删除线,字体大小,字体系列,上标,下标,也许还会添加其他类型。但是为什么在项目中选择了该方法呢?您不认为必须存储允许的属性列表是肮脏的代码吗?我真的很好奇您对这些问题的回答!
青蛙2012年

我不得不处理这样的情况,即当应用程序已经部署时,客户端可以定义一些属性。一些客户端需要一些其他属性,而其他客户端则已过时。我可以使用这种方法来自定义表单,存储的数据集并解决其他问题。我认为它不会生成肮脏的代码。有时您只是无法预测客户将需要哪种信息。
2012年

但是我的客户不需要添加自定义属性。在那种情况下,我认为它看起来有些“ hacky”。你不同意吗?
青蛙

如果您没有面临动态数量的属性问题,则不需要灵活的空间来存储它们。没错:)不过我不同意另一部分。在我看来,在字典/ hashmap / etc中存储属性并不是一个坏方法。
2012年

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.