【发布时间】:2019-07-18 00:25:58
【问题描述】:
我无法在 powershell 中访问同级方法
$group.search.has_member(search)得到成员后是一样的,但是
$group.retrieve.Members() 获取 365 组与本地组的成员的方式不同
所以我试图让.search.has_member(search) 调用.retrieve.Members() 以最大程度地减少代码重复(IRL 大约有 15 个不同的版本,其中一些具有独特的检索方法,一些具有共享方法)。但我无法访问兄弟的方法
我的主要目标是尝试构建一个界面外观,以统一您与 Exchange 邮件对象的交互方式。 365 mailboxes、local mailboxes、365 groups 和 local groups(以及其他)都可以拥有 Members、MemberOf、Email Addresses 和 Distinguished Name,但 DN 是所有对象的属性, Email addresses 属性在 365 和本地组上的格式不同(这会影响 .MatchesSMTP($search)),并且对于 365 组和本地组,检索 Members() 是不同的,并且无论是 365 还是本地组,邮箱和邮件联系人都应该返回 null ,并且 MemberOf 的检索对于每种对象类型都是唯一的。
这会导致相当程度的复杂性。 Originally 我试图首先基于类型(邮箱 vs 组)然后基于服务器(mailbox_365,mailbox_local 等)使用继承来打破它们,但我最终得到了太多重复的代码。交换订单时同样的问题(365_mailbox、365_group 等)。
所以现在我正在尝试基于行为实现抽象,以便在可能的情况下更好地共享代码,并为需要更独特方法的版本分别选择样式/策略。但是.Searches 无法访问.Retrievals。
我想我可以将retrievals 作为参数传递给searches 构造函数,就像我为config 传递的那样,但是如果我开始以更多具有交错依赖的行为类别结束,这种方法就不能很好地扩展。此外,如果我可以让同级访问正常工作,我可以停止将配置作为参数传递并直接访问它们,这应该会进一步清理代码。
下面是一个简化的示例供参考(是的,尽管它很复杂,但它已经大大降低了,我上次统计时最终版本大约有 26 个类)
Class Mail_Factory
{
static [Mail_Interface] BuildExample1()
{
$mail_object = "Pretend 365 group"
return [Mail_Factory]::Build($mail_object)
}
static [Mail_Interface] BuildExample2()
{
$mail_object = "Pretend Local Group"
return [Mail_Factory]::Build($mail_object)
}
static [Mail_Interface] Build($mail_object)
{
[Mail_Interface] $interface = [Mail_Interface]::new()
$interface.config = [Mail_Config]::new($mail_object)
$interface.retrieve = [Mail_Retrieve]::new($interface.config)
$interface.search = [Mail_Search]::new($interface.config)
[Mail_Retrieve_Members_Style] $members_style = switch ($mail_object)
{
("Pretend 365 group") { [Mail_Retrieve_Members_365Group]::new($interface.config) }
("Pretend Local Group") { [Mail_Retrieve_Members_LocalGroup]::new($interface.config) }
}
# notice that we're setting a specific retreival strategy for "members" depending on object type
$interface.config.members_style = $members_style
return $interface
}
}
Class Mail_Interface
{
Mail_Interface(){}
[Mail_Config] $config
[Mail_Retrieve] $retrieve # This is a facade to unify the way we call different kinds of retreivals (directly from settings, derived from settings, shared based on type, or unique to a specific combination of settings)
[Mail_Search] $search # This is a facade for the same reasons as $retreive
[bool] has_member($search) {return $this.search.has_member($search)}
[object] members() {return @($this.retrieve.members())}
}
Class Mail_Config
{
Mail_Config($mail_object) {$this.mail_object = $mail_object}
[Mail_Retrieve_Members_Style] $members_style # set by factory
[object] $mail_object
}
Class Mail_Retrieve
{
Mail_Retrieve($config){$this.config = $config}
[Mail_Config] $config
[object] Members(){return $this.config.members_style.Members()}
}
Class Mail_Retrieve_Members_Style
{
Mail_Retrieve_Members_Style($config){$this.config = $config}
[Mail_Config] $config
[object] Members(){throw("Syle not yet selected")}
}
Class Mail_Retrieve_Members_365Group : Mail_Retrieve_Members_Style
{
Mail_Retrieve_Members_365Group($config) : base($config) {}
# inherited: [Mail_Config] $config
[object] Members(){return "member of 365 group"}
}
Class Mail_Retrieve_Members_LocalGroup : Mail_Retrieve_Members_Style
{
Mail_Retrieve_Members_LocalGroup($config) : base($config) {}
# inherited: [Mail_Config] $config
[object] Members(){return "member of local group"}
}
Class Mail_Search
{
Mail_Search($config){$this.config = $config}
[Mail_Config] $config
[bool] has_member($search)
{
$members = $this.parent.retrieve.members() # !!! Problem exists here !!!
if ($members -contains "$search") {return $true}
else {return $false}
}
}
function TestExample1()
{
# from
# $a.search.has_member()
# we're trying to access
# $a.retrieve.Members()
$a = [Mail_Factory]::BuildExample1()
$member_a = $a.members()[0]
if ($a.has_member($member_a))
{"Success!"}
else
{"Failed, member match incorrect"}
}
function TestExample2()
{
# from
# $b.search.has_member()
# we're trying to access
# $b.retrieve.Members()
$b = [Mail_Factory]::BuildExample2()
$member_b = $b.members()[0]
$b.has_member($member_b)
if ($b.has_member($member_b))
{"Success!"}
else
{"Failed, member match incorrect"}
}
$result_a = TestExample1
$result_b = TestExample2
$result_a
$result_b
这会吐出以下错误(我已用!!! Problem exists here !!! 标记了该行)
You cannot call a method on a null-valued expression.
At line:88 char:9
+ $members = $this.super.retrieve.members() # !!! Problem exist ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
我对这个项目有完全的控制权,如果我以错误的方式处理这个问题,我目前愿意完全重构为不同的方法。我很喜欢使用链式构造函数,特别是如果它们提高了可读性。 我一直在G4G 上探索设计模式,但我对它们的体验仍然是新手
【问题讨论】:
标签: powershell class design-patterns siblings