如何解决违反德米特法案的行为? [英] How to solve the violations of the Law of Demeter?

查看:168
本文介绍了如何解决违反德米特法案的行为?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

一位同事和我为客户设计了一个系统,在我们看来,我们创造了一个很好的干净设计。但是我遇到了一些耦合问题。我可以尝试创建一个包含与我们设计相同问题的示例设计,但是如果您原谅我,我将创建一个解决方案,以支持该问题。



我们正在开发一种为患者注册某些治疗方法的系统。为了避免连接到图像的链接断开,我会将概念UML类图描述为ac#风格类定义。

  class Discipline {} 
class ProtocolKind
{
纪律;
}
class协议
{
ProtocolKind;
ProtocolMedication; //1..*
}
class ProtocolMedication
{
医学;
}
class Medicine
{
AdministrationRoute;
}
class AdministrationRoute {}

我会尝试解释一下关于设计,一个协议是新的治疗模板。一个协议是一定的,有药物需要管理。根据协议,相同药物(除其他外)的剂量可能不同,因此存储在ProtocolMedication类中。 AdministrationRoute是药物与协议管理分开管理和更新/更新的方式。



我发现了以下违反法律的地方的Demeter:



违反德米特法的行为



BLL内部



例如,在ProtocolMedication的业务逻辑内部,有依赖于药物的AdministrationRoute.Soluble属性的规则。代码将成为

  if(!Medicine.AdministrationRoute.Soluble)
{
//验证约束在栏位上
}



资源库



将列出某个学科中所有协议的方法将被写为:

  public IQueryable< Protocol> ListQueryable(Discipline discipline)
{
return ListQueryable()。Where(p =>(p.Kind.Discipline.Id == discipline.Id)); //实体框架需要您比较Id ...
}



用户内部接口



我们使用ASP.NET(没有MVC)作为我们系统的界面,在我看来,这个层目前是最严重的违规。 gridview的数据绑定(必须显示协议的纪律的列必须绑定到Kind.Discipline.Name),这是字符串,所以没有编译时错误

 < asp:TemplateField HeaderText =DisciplineSortExpression =Kind.Discipline.Name> 
< ItemTemplate>
<%#Eval(Kind.Discipline.Name)%>
< / ItemTemplate>
< / asp:TemplateField>

所以我认为实际的问题可能是,什么时候可以更好地看待它Demeter的建议,以及为解决违反德米特法的行为可以做些什么?



我有一些自己的想法,但我会发布他们作为答案,所以他们可以被评论和投票分开。 (我不知道这是否是这样做的,如果没有,我会删除我的答案并将其添加到问题中)。

解决方案

我对Demeter法的后果的理解似乎与DrJokepu的不同 - 每当我将其应用于面向对象的代码时,都会导致更紧密的封装和内聚,而不是添加额外的获取者在程序代码中合同路径。



维基百科的规则为


更正式地,
函数的Demeter法则要求
对象O的方法M只能调用以下类型的
对象的
方法:



  1. O本身

  2. M的参数

  3. 任何创建/实例化的对象在M

  4. O的直接组件对象


如果你有一个把厨房作为参数的方法呃,Demeter说你不能检查厨房的部件,而不是只能检查直接的部件。


编写一堆功能只是为了满足这样的德米特法则

  Kitchen.GetCeilingColour()
/ pre>

看起来像是浪费时间,实际获得是我完成工作的方式


$如果厨房之外的一个方法通过一个厨房,那么严格的Demeter它就不能在GetCeilingColour()的结果上调用任何方法。但是无论哪种方式,关键是要去除对结构的依赖,而不是将结构的表示从一系列链接的方法移动到方法的名称。在Dog类中创建MoveTheLeftHindLegForward()等方法对于完成Demeter来说并不做任何事情。相反,请呼叫dog.walk()并让狗处理自己的腿。


例如,如果要求改变了,我会需要天花板高度?


我会重构代码,以便您正在使用房间和天花板:

  interface RoomVisitor {
void visitFloor(Floor floor)...
void visitCeiling(Ceiling ceiling)...
void visitWall(墙壁...
}

接口房间{accept(RoomVisitor visitor);}

Kitchen.accept(RoomVisitor visitor){
visitor.visitCeiling(this.ceiling);
...
}



您可以通过将天花板的参数传递给visitCeiling方法来进一步消除吸气剂,但往往会引入脆弱的耦合。



将其应用于医学的例子,我期望一个SolubleAdminstrationRoute能够验证该药,或至少打电话该药物的validateForSolubleAdministration方法,如果有药物的类中封装的信息是验证所需的。



然而,Demeter适用于OO系统 - 其中数据被封装在对象内操作数据 - 而不是您正在谈论的系统,它具有不同的层,数据在哑巴,可导航结构中的层之间传递。我没有看到,Demeter可以很容易地应用于这样的系统,就像单片机或基于消息的那样。 (在基于邮件的系统中,您无法浏览任何不在邮件内容中的内容,因此您不用担心Demeter,您是否喜欢)


A colleague and I designed a system for our customer, and in our opinion we created a nice clean design. But I'm having problems with some coupling we've introduced. I could try to create an example design which includes the same problems as our design, but if you forgive me I'll create an extract of our design to support the question.

We're developing a system for the registration of certain treatments for a patients. To avoid having a broken link to image I'll describe the conceptual UML class diagram as a c# style class definition.

class Discipline {}
class ProtocolKind 
{ 
   Discipline; 
}
class Protocol
{
   ProtocolKind;
   ProtocolMedication; //1..*
}
class ProtocolMedication
{
   Medicine;
}
class Medicine
{
   AdministrationRoute;
}
class AdministrationRoute {}

I'll try to explain a bit about the design, a protocol is the template for a new treatment. And a protocol is of a certain Kind and has medications which need to be administered. Per protocol the dosage can differ for the same medicine (amongst other things), so that's stored in the ProtocolMedication class. AdministrationRoute is the way the medicine is administered and iscreated/updated separately from the protocol management.

I've found the following places which we'll have a violation of the Law of Demeter:

Violations of the Law of Demeter

Inside of the BLL

For example, inside the business logic of the ProtocolMedication there are rules which depend on the AdministrationRoute.Soluble property of the medicine. The code would become

if (!Medicine.AdministrationRoute.Soluble)
{
   //validate constrains on fields
}

Inside the repositories

A method which would list all the protocols in a certain Discipline would be written as:

public IQueryable<Protocol> ListQueryable(Discipline discipline)
{
    return ListQueryable().Where(p => (p.Kind.Discipline.Id == discipline.Id)); // Entity Frameworks needs you to compare the Id...
}

Inside the User Interface

We use ASP.NET (no MVC) for the interface of our system, in my opinion this layer currently has the worst violations. The databinding of a gridview (a column which must display the Discipline of a protocol must bind to Kind.Discipline.Name), which are strings, so no compile time errors.

<asp:TemplateField HeaderText="Discipline" SortExpression="Kind.Discipline.Name">
   <ItemTemplate>
      <%# Eval("Kind.Discipline.Name")%>
   </ItemTemplate>
</asp:TemplateField>

So I think the actual question might be, when would it be okay to look at it more as the Suggestion of Demeter, and what can be done to solve the violations of the Law of Demeter?

I've got a few idea's of myself but I'll post them as answers so they can be commented and voted on seperatly. (I'm not sure this is the SO way to do it, if not, I'll delete my answers and add them to the question).

解决方案

My understanding of consequences of the Law of Demeter seems to be different to DrJokepu's - whenever I've applied it to object oriented code it's resulted in tighter encapsulation and cohesion, rather than the addition of extra getters to contract paths in procedural code.

Wikipedia has the rule as

More formally, the Law of Demeter for functions requires that a method M of an object O may only invoke the methods of the following kinds of objects:

  1. O itself
  2. M's parameters
  3. any objects created/instantiated within M
  4. O's direct component objects

If you have a method which takes 'kitchen' as a parameter, Demeter says you cannot inspect the components of the kitchen, not that you can only inspect the immediate components.

Writing a bunch of functions just to satisfy the Law of Demeter like this

Kitchen.GetCeilingColour()

just looks like a total waste of time for me and actually gets is my way to get things done

If a method outside of Kitchen is passed a kitchen, by strict Demeter it can't call any methods on the result of GetCeilingColour() on it either.

But either way, the point is to remove the dependency on structure rather than moving the representation of the structure from a sequence of chained methods to the name of the method. Making methods such as MoveTheLeftHindLegForward() in a Dog class doesn't do anything towards fulfilling Demeter. Instead, call dog.walk() and let the dog handle its own legs.

For example, what if the requirements change and I will need the ceiling height too?

I'd refactor the code so that you are working with room and ceilings:

interface RoomVisitor {
  void visitFloor (Floor floor) ...
  void visitCeiling (Ceiling ceiling) ...
  void visitWall (Wall wall ...
}

interface Room { accept (RoomVisitor visitor) ; }

Kitchen.accept(RoomVisitor visitor) {
   visitor.visitCeiling(this.ceiling);
   ...
}

Or you can go further and eliminate getters totally by passing the parameters of the ceiling to the visitCeiling method, but that often introduces a brittle coupling.

Applying it to the medical example, I'd expect a SolubleAdminstrationRoute to be able to validate the medicine, or at least call the medicine's validateForSolubleAdministration method if there's information encapsulated in the medicine's class which is required for the validation.

However, Demeter applies to OO systems - where data is encapsulated within the objects which operate upon the data - rather than the system you're talking about, which has different layers an data being passed between the layers in dumb, navigatable structures. I don't see that Demeter can necessarily be applied to such systems as easily as to monolithic or message based ones. (In a message based system, you can't navigate to anything which isn't in the grams of the message, so you're stuck with Demeter whether you like it or not)

这篇关于如何解决违反德米特法案的行为?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆