在powershell 5中,我遇到了一个奇怪的类继承问题。
我想强制我们在安装过程中像[class]::new($mailbox_object)
一样传递一个对象,而我打算通过使[class]::new()
抛出一个错误(如果未分配关联的对象)来做到这一点(例如由一个子构造函数)。
但是powershell在调用传递给对象的子构造函数之前正在调用 empty 父构造函数,但我无法弄清楚这是错误还是预期的错误,更重要的是,我们如何执行该错误在创建时必须给一个对象
说设计模式:我正在尝试实现所谓的统一接口模式,这是一个Facade模式,用于简化/统一与相似但类型不同的对象的交互,其中使用“策略”模式选择这些对象的操作,该策略是在创建时由Facade自动选择的(当前是通过尝试使用隐藏在Facade中的不可见Factory来实现)
IRL示例:尝试为Exchange邮箱/组对象创建统一接口,并实现MemberOf函数(以返回其所属的组)。但是邮箱和组使用不同的命令(尽管具有匹配功能),并且365和本地版本也使用了不同的命令(get-unifiedgroup而不是get-distributiongroup),因此,我试图将这种复杂性隐藏在统一的Facade中,以确保清晰度和可用性< / p>
我愿意改变自己的方法,特别是如果有更好的方法可以做到这一点。请记住,至少会有以下不同类型的对象,每个对象都需要自己实现.MemberOf():Interface_Mailbox_365
,Interface_Mailbox_OnPremises
,Interface_Group_365
,{{1 }},最终我可能会实现离线版本和通用版本。
MRE,带有>的行是输出。由于我将其范围缩小到创建接口的问题,因此我没有包括Facade或Factory,但是如果最终需要它们,可以添加它们。
Interface_Group_OnPremises
请注意,即使我们调用class Interface_MailObject
{
$MailObject = "Interface_MailObject class - initial"
Interface_MailObject(){write-warning "Interface_MailObject::new() MailObject: {$($this.MailObject)}"}
static [Interface_MailObject] Build($object)
{
if
($object -eq "Mailbox Standin")
{return [Interface_Mailbox_365]::new($object)}
else
{throw("we don't reach here")}
}
}
Class Interface_Mailbox : Interface_MailObject
{
$MailObject = "Interface_Mailbox class - initial"
Interface_Mailbox () {write-warning "Interface_Mailbox::new() MailObject: {$($this.MailObject)}"}
Interface_Mailbox ($MailObject) {$this.MailObject = "Interface_Mailbox class - {$($MailObject)}"}
}
Class Interface_Mailbox_365 : Interface_Mailbox
{
$MailObject = "Interface_Mailbox_365 class - initial"
Interface_Mailbox_365 () {write-warning "Interface_Mailbox_365::new() MailObject: {$($this.MailObject)}"}
Interface_Mailbox_365 ($MailObject) {$this.MailObject = "Interface_Mailbox_365 class - {$($MailObject)}"}
[object[]] MemberOf(){throw("Interface_Mailbox_365.MemberOf TBD")}
}
[Interface_MailObject]::new("Mailbox Standin")|tee -va a
> WARNING: Interface_MailObject::new() MailObject: {Interface_Mailbox_365 class - initial}
> WARNING: Interface_Mailbox::new() MailObject: {Interface_Mailbox_365 class - initial}
>
> MailObject
> ----------
> Interface_Mailbox_365 class - {Mailbox Standin}
,powershell也会在运行我们调用的父级构造函数之前先执行祖父母的空构造函数,然后执行父级的空构造函数。
如果它们以其他顺序执行,那就没问题了。如果他们调用匹配相同参数qty和type的父构造函数,那也没问题
但是它什么都不做,而且我不知道如何在Singleton工厂中不使用一些怪异的杂技来解决它,这似乎是对微不足道的微管理,这对于应该是很常见的事情(初始化期间需要输入参数) ),所以我猜我正在忽略某些东西
答案 0 :(得分:1)
感谢@Mathias R. Jessen帮助我解决了问题。
起初,我以为我必须将立面/工厂与模板分离,而不是能够使它们属于同一类。不幸的是,这意味着我正在呼叫[MailObject_Interface]::Build($object)
,但没有返回[MailObject_Interface]
类型。
做完一些研究后,我意识到Mathias所说的是子构造函数child(object){}
的意思是child(object):base(){}
,您可以通过明确声明child(object):base(object){}
再加上一个额外的部分来验证父母身份,我就无法取得成功
Class MailObject_Interface
{
[string] $MailObject
MailObject_Interface ()
{throw("You must call ::Build(`$object), because we return specialized types based on the mail object")}
MailObject_Interface ($object) {[MailObject_Interface]::new()} # this triggers the error above
MailObject_Interface ($object, $codephrase)
{
Write-Warning "calling MailObject_Interface::New($($object), $($codephrase)) {$($this.MailObject)}"
# the Codephrase ensures
# either we're being called from one of our children,
# or whomever calls us is aware of our internal workings and is taking responsibility for making sure we're handled correctly
if
($codephrase -eq "Shazam!")
{$this.MailObject = $object}
else
{[MailObject_Interface]::new()} # this triggers the error above
}
# We run through ::Build instead of ::New because we want to return a child typed object rather than ourselves
static [MailObject_Interface] Build($object)
{
if
($object -eq "Mailbox Standin")
{return [Interface_Mailbox_365]::new($object)}
else
{throw("we don't reach here")}
}
}
Class Interface_MailObject_Template : MailObject_Interface
{
Interface_MailObject_Template ($object) : base ($object, "Shazam!") {Write-Warning "calling Interface_MailObject_Template::New($($object)) {$($this.MailObject)}"}
[object[]] MemberOf(){throw(".MemberOf will be type+context specific")}
}
Class Interface_Mailbox : Interface_MailObject_Template
{
Interface_Mailbox ($object) : base ($object) {Write-Warning "calling Interface_Mailbox::New($($object)) {$($this.MailObject)}"}
[object[]] MemberOf(){throw("Mailbox.MemberOf will be context specific")}
}
Class Interface_Mailbox_365 : Interface_Mailbox
{
Interface_Mailbox_365 ($object) : base ($object) {Write-Warning "calling Interface_Mailbox_365::New($($object)) {$($this.MailObject)}"}
[object[]] MemberOf(){throw("Interface_Mailbox_365.MemberOf TBD")}
}
#\/ Rough Tests \/#
# should succeed
function Test_Correct()
{
Try
{
[MailObject_Interface]$a = [MailObject_Interface]::Build("Mailbox Standin")
return "Succeded ($a)"
}
Catch
{return "Failed"}
}
# should fail
function Test_New_WithObject_MissingCodephrase()
{
Try
{
$a = [MailObject_Interface]::New("Mailbox Standin")
return "Succeded: ($a)"
}
Catch
{return "Failed"}
}
# should fail
function Test_EmptyBuild()
{
Try
{
$a = [MailObject_Interface]::Build()
return "Succeded: ($a)"
}
Catch
{return "Failed"}
}
# should fail
function Test_EmptyNew()
{
Try
{
$a = [MailObject_Interface]::New()
return "Succeded: ($a)"
}
Catch
{return "Failed"}
}
"$(Test_Correct):`tTest_Correct (should have succeeded)"
"$(Test_New_WithObject_MissingCodephrase):`tTest_New_WithObject_MissingCodephrase (should have failed)"
"$(Test_EmptyBuild):`tTest_EmptyBuild (should have failed)"
"$(Test_EmptyNew):`tTest_EmptyNew (should have failed)"
这是测试结果
> WARNING: calling MailObject_Interface::New(Mailbox Standin, Shazam!) {}
> WARNING: calling Interface_MailObject_Template::New(Mailbox Standin) {Mailbox Standin}
> WARNING: calling Interface_Mailbox::New(Mailbox Standin) {Mailbox Standin}
> WARNING: calling Interface_Mailbox_365::New(Mailbox Standin) {Mailbox Standin}
> Succeded (Interface_Mailbox_365): Test_Correct (should have succeeded)
> Failed: Test_New_WithObject_MissingCodephrase (should have failed)
> Failed: Test_EmptyBuild (should have failed)
> Failed: Test_EmptyNew (should have failed)
也对“测试”功能中的异常格式感到抱歉。我忘了将支架的压痕转换为正常的标准,我使用了一种非标准的方法,我发现它更具功能性,因为它使用空格将控制逻辑框架化,从而使它更自然地跟随您在略读时的视线范围