Feature Envy(依恋情结)
官方的:函数对某个类的兴趣高过对自己所处类的兴趣。
影响:数据和行为不在一处,修改不可控。
Demo:媒婆、一小伙、一小姑娘
场景一:函数的全部数据都来自于另外一个类
媒婆、小伙先出场
public class Boy { public string Name { get; set; } public int Age { get; set; } public string Adress { get; set; } public bool IsSinglehood { get; set; } public bool IsHightRichHandsome { get; set; } } public class WomanMatchMaker { private readonly Boy boy; ... public string GetBoyInformation() { return string.Format("Name: {0} Age: {1} Adress: {2} the boys is {3} and he is {4}", boy.Name, boy.Age, boy.Adress, (boy.IsSinglehood ? "Singlehood " : "married"), (boy.IsHightRichHandsome ? "HightRichHandsome" : "DiaoSi")); } }
从上面代码看出:GetBoyInformation函数中所有数据都是从Boy类中获取。如果Boy中的属性发生变化,就要改WomanMatchMaker类,修改多处。为了让数据和行为变化在一处,Boy应该负责提供本人信息的这种行为。
public class Boy { ... public string GetInformation() { return string.Format("Name: {0} Age: {1} Adress: {2} the boys is {3} and he is {4}", Name, Age, Adress, (IsSinglehood ? "Singlehood " : "married"), (IsHightRichHandsome ? "HightRichHandsome" : "DiaoSi")); } } public class WomanMatchmaker { private readonly Boy boy; ... public string GetBoyInformation() { return boy.GetInformation(); } }
将GetBoyInformation函数Move到Boy类中。然后WomanMatchMarker中用一委托。
场景二:函数有一部分数据来自于另一个类。
现在需求稍微有点变动。需要提供男孩信息的同时要提供媒婆信息。
public class WomanMatchmaker { public string Name { get; set; } public string Adress { get; set; } private readonly Boy boy; ... public string GetBoyInformationWithComeFromInformation() { return string.Format("Name: {0} Age: {1} Adress: {2} the boys is {3} and he is {4}, {5}", boy.Name, boy.Age, boy.Adress, (boy.IsSinglehood ? "Singlehood " : "married"), (boy.IsHightRichHandsome ? "HightRichHandsome" : "DiaoSi"), GetInformationComeFrom()); } private string GetInformationComeFrom() { return string.Format("Information comes from: {0} Adress: {1}", Name, Adress); } }
此函数中有部分使用另一个类的数据。同第一种做法稍有不同,先把从Boy中来的数据Extract 到一个独立函数中,在把它移到它想去的地方。那么此方法就变成这个样子了。
public class WomanMatchMaker { public string Name { get; set; } public string Adress { get; set; } private readonly Boy boy; ... public string GetBoyInformationWithComeFromInformation() { return boy.GetInformation() + GetInformationComeFrom(); } private string GetInformationComeFrom() { return string.Format("Information comes from: {0} Adress: {1}", Name, Adress); } }
场景三:函数使用多个类的数据
等了这么久,姑娘终于出场了。媒婆要看看小伙子和姑娘是否合适。
有了上面的两个场景。再来看看这个方法有没有Refactor的Sense。
public string MatchedPairResult() { //boy information var boyInfo = string.Format("Name: {0} Age: {1} Adress: {2}...", boy.Name, boy.Age, boy.Adress); //girl information var girlInfo = string.Format("Name: {0} Age: {1} Adress: {2}...", girl.Name, girl.Age, girl.Adress); return (RuleMatching(boyInfo, girlInfo) ? "To be together!" : "Improper!") + GetInformationComeFrom(); }
这个函数用到了多个类的数据。那么我们就分别把它们提炼到独立函数中,在分别送它们想去的地方。
public class WomanMatchMaker { ... public string MatchedPairResult() { //boy information var boyInfo = boy.GetInformation(); //girl information var girlInfo = girl.GetInformation(); return (RuleMatching(boyInfo, girlInfo) ? "To be together!" : "Improper!") + GetInformationComeFrom(); } ... }
经过一番重构之后,他们终于幸福的在一起了。
总结:
1、函数全部数据来自另外一个类
做法:将数据提炼到一个独立函数中 Move method。
2、函数部分数据来自另外一个类
做法:将“部分数据”提炼到一个函数中 Move method。
3、函数的数据来自不同类
做法:将数据分类,分别提炼各自的独立的函数,在将这些函数移到各自属于的类中。