Well, I think that it boils down to the difference between good and good enough.
While in most cases you can avoid the use of constants by implementing other patterns (strategy or perhaps flyweight), there is something to be said for not needing a half dozen other classes to represent a concept. I think what it boils down to, is how likely is there a need for other constants. In other words, is there a need to extend the ENUM provided by the constants on the interface. If you can foresee needing to expand it, then go with a more formal pattern. If not, then it may suffice (it'll be good enough, and hence be less code to write and test). Here's an example of a good enough and a bad use:
Now, the reason that I chose those examples is simple. The User interface is defining an enum of user types. This is very likely to expand over time and would be better suited by another pattern. But the HTTPRequest_1_1 is a decent use-case, since the enum is defined by RFC2616 and will not change for the lifetime of the class.
In general, I don't see the problem with constants and class constants as being a global problem. I see it as a dependency problem. It's a narrow distinction, but a definite one. I see global problems as in global variables which are not enforced, and as such create a soft global dependency. But a hard-coded class creates an enforced dependency, and as such create a hard global dependency. So both are dependencies. But I consider the global to be far worse since it's not enforced... Which is why I don't like to lump class dependencies with global dependencies under the same banner...
If you write MyClass::FOO, you're hard-coded to the implementation details of MyClass. This creates a hard-coupling, which makes your code less flexible, and as such should be avoided. However, interfaces exist to permit exactly this type of coupling. Therefore MyInterface::FOO doesn't introduce any concrete coupling. With that said, I wouldn't introduce an interface just to add a constant to it.
So if you're using interfaces, and you're very sure that you (or anyone else for that matter) won't need additional values, then I don't really see a huge issue with the interface constants... The best designs wouldn't include any constants or conditionals or magic-numbers or magic-strings or hard-coded anything. However, that adds additional time to the development, as you must consider the uses. My view is that most times it's absolutely worth taking the additional time to build a great solid design. But there are times when good enough really is acceptable (and it takes an experienced developer to understand the difference), and in those cases it's fine.
I think that its usually better to handle constants, specially enumerated constants, as a separate type ("class") from your interface:
define(TYPE_CONNECT, 'connect');
define(TYPE_DELETE , 'delete');
define(TYPE_GET , 'get');
define(TYPE_HEAD , 'head');
define(TYPE_OPTIONS, 'options');
define(TYPE_POST , 'post');
define(TYPE_PUT , 'put');
interface IFoo
{
function /* int */ readSomething();
function /* void */ ExecuteSomething(/* int */ param);
}
class CBar implements IFoo
{
function /* int */ readSomething() { ...}
function /* void */ ExecuteSomething(/* int */ param) { ... }
}
or, if you want to use a class as a namespace:
class TypeHTTP_Enums
{
const TYPE_CONNECT = 'connect';
const TYPE_DELETE = 'delete';
const TYPE_GET = 'get';
const TYPE_HEAD = 'head';
const TYPE_OPTIONS = 'options';
const TYPE_POST = 'post';
const TYPE_PUT = 'put';
}
interface IFoo
{
function /* int */ readSomething();
function /* void */ ExecuteSomething(/* int */ param);
}
class CBar implements IFoo
{
function /* int */ readSomething() { ...}
function /* void */ ExecuteSomething(/* int */ param) { ... }
}
Its not that you are using just constants, you are using the concept of enumerated values or enumerations, which a set of restricted values, are considered a specific type, with a specific usage ("domain" ? )
发布评论
评论(2)
嗯,我认为这可以归结为好和足够好之间的区别。
虽然在大多数情况下,您可以通过实现其他模式(策略或蝇量级)来避免使用常量,但需要注意的是,不需要六个其他类来表示一个概念。我认为归根结底,就是需要其他常数的可能性有多大。也就是说,是否需要扩展接口上常量提供的ENUM。如果您可以预见需要扩展它,那么就采用更正式的模式。如果没有,那么它可能就足够了(它会足够好,因此需要编写和测试的代码更少)。下面是一个足够好的使用和一个不好的使用的示例:
不好:
足够好:
现在,我选择这些示例的原因很简单。
User
接口定义了用户类型的枚举。随着时间的推移,这种情况很可能会扩大,并且更适合另一种模式。但HTTPRequest_1_1
是一个不错的用例,因为枚举是由 RFC2616 定义的,并且在类的生命周期内不会更改。一般来说,我不认为常量和类常量的问题是一个全局问题。我认为这是一个依赖性问题。这是一种狭隘的区别,但却是明确的。我看到全局问题是在未强制执行的全局变量中,因此创建了软全局依赖。但是硬编码的类会创建强制依赖项,从而创建硬全局依赖项。所以两者都是依赖关系。但我认为全局要糟糕得多,因为它没有被强制执行......这就是为什么我不喜欢将类依赖与全局依赖混为一谈。 em> 在同一旗帜下...
如果您编写
MyClass::FOO
,您将被硬编码到MyClass
的实现细节。这会产生硬耦合,从而降低代码的灵活性,因此应该避免。然而,接口的存在正是为了允许这种类型的耦合。因此MyInterface::FOO
不会引入任何具体的耦合。话虽如此,我不会仅仅为了向其添加常量而引入接口。因此,如果您正在使用接口,并且您非常确定您(或任何其他人)不需要额外的值,那么我真的不认为有什么大问题接口常量...最好的设计不会包含任何常量或条件或幻数或幻数字符串或硬编码的任何内容。但是,这会增加开发时间,因为您必须考虑用途。我的观点是,大多数时候绝对值得花额外的时间来构建出色的可靠设计。但有时足够好确实是可以接受的(并且需要经验丰富的开发人员来理解其中的差异),在这种情况下这很好。
再说一遍,这只是我的看法......
Well, I think that it boils down to the difference between good and good enough.
While in most cases you can avoid the use of constants by implementing other patterns (strategy or perhaps flyweight), there is something to be said for not needing a half dozen other classes to represent a concept. I think what it boils down to, is how likely is there a need for other constants. In other words, is there a need to extend the ENUM provided by the constants on the interface. If you can foresee needing to expand it, then go with a more formal pattern. If not, then it may suffice (it'll be good enough, and hence be less code to write and test). Here's an example of a good enough and a bad use:
Bad:
Good Enough:
Now, the reason that I chose those examples is simple. The
User
interface is defining an enum of user types. This is very likely to expand over time and would be better suited by another pattern. But theHTTPRequest_1_1
is a decent use-case, since the enum is defined by RFC2616 and will not change for the lifetime of the class.In general, I don't see the problem with constants and class constants as being a global problem. I see it as a dependency problem. It's a narrow distinction, but a definite one. I see global problems as in global variables which are not enforced, and as such create a soft global dependency. But a hard-coded class creates an enforced dependency, and as such create a hard global dependency. So both are dependencies. But I consider the global to be far worse since it's not enforced... Which is why I don't like to lump class dependencies with global dependencies under the same banner...
If you write
MyClass::FOO
, you're hard-coded to the implementation details ofMyClass
. This creates a hard-coupling, which makes your code less flexible, and as such should be avoided. However, interfaces exist to permit exactly this type of coupling. ThereforeMyInterface::FOO
doesn't introduce any concrete coupling. With that said, I wouldn't introduce an interface just to add a constant to it.So if you're using interfaces, and you're very sure that you (or anyone else for that matter) won't need additional values, then I don't really see a huge issue with the interface constants... The best designs wouldn't include any constants or conditionals or magic-numbers or magic-strings or hard-coded anything. However, that adds additional time to the development, as you must consider the uses. My view is that most times it's absolutely worth taking the additional time to build a great solid design. But there are times when good enough really is acceptable (and it takes an experienced developer to understand the difference), and in those cases it's fine.
Again, that's just my view on it...
我认为通常最好将常量(特别是枚举常量)作为接口中的单独类型(“类”)来处理:
或者,如果您想使用类作为命名空间:
这并不是说您只使用常量,您使用枚举值或枚举的概念,其中一组受限值被视为具有特定用法的特定类型(“域”?)
I think that its usually better to handle constants, specially enumerated constants, as a separate type ("class") from your interface:
or, if you want to use a class as a namespace:
Its not that you are using just constants, you are using the concept of enumerated values or enumerations, which a set of restricted values, are considered a specific type, with a specific usage ("domain" ? )