摘要
我试图在javascript中正确地实现继承和封装,就像在基于类的语言(如c#)中一样.
丑陋的部分是受保护的成员在私有实例中有多个副本,只能通过闭包访问,除了将这些成员刷新到私有实例之外,我没有任何想法.
如果有可能,我想摆脱我transmit和transfer我的代码Function.extend.
更新 对于对引用或研究感兴趣的人,这里是源代码存储库:
故事
由于程序集可能是一个超出javascript范围的概念,我不考虑internal修改器,但是public,protected和private.
public和private修饰语并不难实现; 但是继承,protected非常棘手.然而,使用javascript并不是一个推荐的事情,我读过的大多数文章都说带有特殊字符的前缀并记录它.
但似乎我坚持使用javascript来模拟基于类的语言..我偷了这个想法并以我的方式实现,代码在这篇文章的后面.
场景背后的想法是使用更高的原型提高可访问性,并使用闭包访问最高的原型.
假设我们有三个原型A,D并且G,它看起来像

因为对象不可能是另一种不属于原型链的类型的实例; 我选择的方式是protected水平链接水平并从声明类型的原型复制成员.这使得嵌套类成为可能,因为在较少派生类型上声明的成员可以传播到更多派生类型; transmit我的代码中的方法是这样做的.如果A,D并G拥有自己的受保护成员,它看起来像:

用于访问私有实例的闭包是this[''].它需要一个用于识别类的参数.修饰符支架正好类标识符,命名y中Function.extend和_测试代码,它不应该被类声明暴露在外.它也被用作快捷方式this[''].
_['base']事实上,不仅是基础构造函数调用者,还有私有实例创建者.它this['']使用继承为每个构造函数创建私有实例和更新,因此应始终在构造函数中调用它.
虽然私有实例可以访问公共成员,但不应该使用它来更改它们,因为this['']在访问公共成员时不能保证调用它们.但访问私有实例是; recent记住最近访问的私有实例,如果有更改,则更新受保护的成员.
我的问题是,我怎样才能摆脱受保护成员的这种清新?是否有更好的想法来实现更真实的封装?
ps:我实际上不想要一个使用非标准方法/属性的解决方案..如果使用的方法/属性对旧浏览器来说过于时尚,那么填充更好.
Function.extend …
好的,这让我烦恼..我知道我已经在某个地方读过它,谷歌没有帮助.
未指定访问修饰符的方法的可访问性级别是什么?
void Foo()
{
//code
}
Run Code Online (Sandbox Code Playgroud)
我想说,internal但我不是百分百肯定.
编译器(clang-5.0.0,GCC-7.3,ICC-18和MSVC-19)发散的成员的可访问性WRT A下面.
class A {
template <class> static constexpr int f() { return 0; }
template <int> struct B {};
template <class T> using C = B<f<T>()>;
};
Run Code Online (Sandbox Code Playgroud)
确实,请考虑以下用法:
template <class T> using D = A::C<T>;
int main() {
// | clang | gcc | icc | msvc
(void) A::f<int>(); // 1: | f | f | f | f, (C)
(void) A::B<0>{}; // 2: | B | | B | …Run Code Online (Sandbox Code Playgroud) 首先,我已经阅读了关于这个主题的帖子列表,并且由于我对封装和字段修饰符(private,public..ect)的了解,我不觉得我已经掌握了属性.
我学习的C#的一个主要方面是使用封装在代码中保护数据的重要性.我认为'我理解这是因为使用修饰符的能力(私人,公共,内部,受保护).然而,在了解了属性之后,我不仅理解了属性的使用,而且还理解了C#中数据保护(我理解为封装)的整体重要性/能力.
更具体地说,当我到达C#中的属性时,我读过的所有内容都是你应该尝试使用它们代替字段,因为:
1)当您直接直接访问字段时,它们允许您更改数据类型.
2)它们为数据访问增加了一定程度的保护
然而,根据我的想法,我已经了解了字段修饰符的使用#2,在我看来属性只是生成了额外的代码,除非你有一些理由改变类型(#1) - 因为你是(或多或少)创建隐藏方法来访问字段而不是直接访问.
然后可以将整个修饰符添加到属性中,这进一步使我对属性访问数据的需要的理解变得复杂.
我已经阅读了不同作者关于"属性"的一些章节,并且没有人真正解释过对属性与字段与封装(以及良好的编程方法)的良好理解.
有人能解释一下:
1)为什么我想要使用属性而不是字段(特别是当它出现时我只是添加额外的代码
2)在跟踪其他人的代码时,有关识别属性的使用以及不将它们视为简单方法(除了get; set明显)之外的任何提示吗?
3)任何关于何时使用什么的良好编程方法的一般经验法则?
感谢和抱歉这篇长篇文章 - 我不想只问一个问题100x而不解释为什么我再问它.
在我脑海中,我是一个有很多人的新手,还有很多用C++体验过的东西!有些东西我觉得很混乱,而且是公共变量的使用,我见过这样的大量代码:
class Foo {
private:
int m_somePrivateVar;
public:
void setThatPrivateVar (int const & new_val) {
m_somePrivateVar = new_val;
}
int getThatPrivateVar (void) const {
return m_somePrivateVar;
}
};
Run Code Online (Sandbox Code Playgroud)
为什么有人会隐藏该变量并实现访问器和更改器,当它们没有完成任何操作时,只需要接收新值(没有范围检查等)或返回值而不是原样?好吧,我听说过一些原因,其中一些原因在某些情况下是令人信服的,但想象一下如此实现一个庞大的类,有很多变量,不需要任何检查和东西!我这样问你,你什么时候使用公共变量?你根本使用它吗?
虽然对类设计中的一些事实感到困惑,特别是函数是否应该是成员,但我查看了有效的c ++并找到了第23项,即将非成员非友元函数更喜欢成员函数.第一手阅读Web浏览器示例有一定意义,但是该示例中的便捷函数(在本书中命名为非成员函数)会改变类的状态,不是吗?
所以,第一个问题,他们不应该成为会员吗?
进一步阅读,他认为STL函数,实际上某些类没有实现的函数是在stl中实现的.继他们演变成被包装到一些合理的命名空间,如一些便利功能,这本书的想法std::sort,std::copy从algorithm.例如,vector类没有sort函数,并且使用stl sort函数,因此它不是向量类的成员.但是也可以将相同的推理延伸到向量类中的某些其他函数,例如,assign这样也不能作为成员实现,而是作为便利函数实现.但是,这也会改变对象的内部状态,例如它操作的排序.那么这个微妙但重要(我猜)问题背后的理由是什么呢?
如果你有权访问这本书,你可以为我澄清这些要点吗?
c++ encapsulation member-functions effective-c++ non-member-functions
为什么编译:
class FooBase
{
protected:
void fooBase(void);
};
class Foo : public FooBase
{
public:
void foo(Foo& fooBar)
{
fooBar.fooBase();
}
};
Run Code Online (Sandbox Code Playgroud)
但这不是吗?
class FooBase
{
protected:
void fooBase(void);
};
class Foo : public FooBase
{
public:
void foo(FooBase& fooBar)
{
fooBar.fooBase();
}
};
Run Code Online (Sandbox Code Playgroud)
一方面,C++为该类的所有实例授予对私有/受保护成员的访问权限,但另一方面,它不授予对所有子类实例的基类的受保护成员的访问权限.这看起来与我不一致.
我已经使用VC++和ideone.com测试了编译,并且编译了第一个但不是第二个代码片段.
我理解PROPERTIES优于FIELDS的优点,但我觉得使用自动实现的属性优于MANUAL实现的属性并不能提供任何其他优势,除了使代码更简洁一些.
我觉得使用起来更舒服:
private string _postalCode;
public string PostalCode
{
get { return _postalCode; }
set { _postalCode = value; }
}
Run Code Online (Sandbox Code Playgroud)
代替:
public string PostalCode { get; set; }
Run Code Online (Sandbox Code Playgroud)
主要是因为如果我想做任何类型的get和set的自定义实现,我必须创建自己的属性,无论如何由私有字段支持.那么为什么不从头开始咬住子弹并立即给予所有属性这种灵活性,以保持一致性?考虑到您在Visual Studio中所做的一切都是单击您的私有字段名称,然后按Ctrl + E,这真的不需要额外的一秒,而且您已经完成了.如果我手动完成,那么我最终会出现不一致的情况,其中有一些手动创建的公共属性由私有字段和一些自动实现的属性支持.随着它的一致性,我感觉好多了,无论是全自动还是全手动.
这只是我吗?我错过了什么吗?我错了什么?我是否过分强调一致性?我总能找到关于C#功能的合理讨论,并且几乎总有优点和缺点,但在这种情况下,我真的找不到任何建议不使用自动实现属性的人.
如何在不破坏封装的情况下执行依赖注入?
public Car {
public float getSpeed();
}
Run Code Online (Sandbox Code Playgroud)
注意:为清楚起见,省略了其他方法和属性(例如PushBrake(),PushGas(),SetWheelPosition())
这很好用; 你不知道我的对象getSpeed是如何实现的- 它是" 封装的 ".
实际上我的对象实现getSpeed为:
public Car {
private m_speed;
public float getSpeed( return m_speed; );
}
Run Code Online (Sandbox Code Playgroud)
一切都很好.有人建造我的Car物体,捣碎踏板,喇叭,方向盘,汽车响应.
现在让我说我改变了我的汽车的内部实现细节:
public Car {
private Engine m_engine;
private float m_currentGearRatio;
public float getSpeed( return m_engine.getRpm*m_currentGearRatio; );
}
Run Code Online (Sandbox Code Playgroud)
一切都很好.将Car是继二OO正确的原则,隐藏的细节如何采取某些措施.这使得呼叫者可以解决他的问题,而不是试图了解汽车的工作原理.它还让我可以自由地改变我的实现.
但依赖注入会迫使我将我的类暴露给Engine我没有创建或初始化的对象.更糟糕的是,我现在已经暴露了我Car甚至有一个引擎:
public Car {
public constructor(Engine engine);
public float getSpeed();
}
Run Code Online (Sandbox Code Playgroud)
现在,外面的词语意识到我使用的是 …
language-agnostic oop unit-testing encapsulation dependency-injection
encapsulation ×10
c# ×4
c++ ×4
field ×2
inheritance ×2
oop ×2
properties ×2
.net ×1
clang ×1
gcc ×1
javascript ×1
php ×1
private ×1
protected ×1
unit-testing ×1