减少初学者所需的耦合简单示例
本文关键字:耦合 简单 初学者 | 更新日期: 2023-09-27 18:33:41
刚从大学毕业,遇到了一些需要减少耦合的代码。但我并不完全理解所有的概念,想要一个简单的例子来帮助我。为了帮助您入门,我有一个带有单个字段 name 的 person 类。我在该类中有一个连接一些文本的方法。
我知道这是一个愚蠢的例子,大多数人永远不会考虑在这样简单的情况下减少耦合,但我只想要一个简单的例子来帮助我完全理解代码和概念。
在主窗口后面的代码中,我放了一个文本框和一个按钮。当窗口加载时,它显示人员 x 姓名字段的当前值。单击该按钮时,将调用 x.PersonAddText 方法。目前,此示例的耦合计算为 8。3 表示按钮单击事件,3 表示窗口加载事件。
有什么办法,使用此示例,我们可以将其降低到小于其中之一或两个。
下面是我的所有代码:
我的人类:
public class Person
{
//Fields
private string name;
//Properties
public string Name
{
get { return name; }
set { name = value; }
}
//Constructors
public Person()
{
name = "joe";
}
//Methods
public string PersonAddText(string text)
{
return name += " - " + text;
}
//Interfaces (or additional code below here please to aid understanding)
}
我的代码隐藏:
Person x = new Person();
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
txtname.Text = x.Name;
}
private void button1_Click(object sender, RoutedEventArgs e)
{
txtname.Text = x.PersonAddText(txtname.Text);
txtname.Text = x.Name;
}
我的简单 XAML:
<Grid>
<TextBox Name="txtname" Margin="12,12,12,0" Height="23" VerticalAlignment="Top" />
<Button Content="Add Text" Margin="12,41,12,0" Name="button1" VerticalAlignment="Top" Click="button1_Click" />
</Grid>
我很难理解互联网上解释这一点的教程。据我所知,有 3 种方法可以做到这一点(如果可能的话,将我上面的代码转换为所有三种方法的示例会很好(:
- 服务定位器
- 依赖注入
- 控制反转 (IoC(
解释我读过的东西的文章非常好,但这些示例与我无关,因为他使用 VB 和数据库连接字符串 ASP.Net。这与我的需求完全相反,我不想在学习概念的同时考虑如何翻译代码,也不想考虑如何将其应用于相关内容。虽然这个例子很好,但它太多了,我真的很感激任何额外的帮助。
编辑历史记录:更正了拼写。添加了以下内容以澄清我的问题:
我理解耦合和内聚背后的理论,以及为什么你应该减少一个而增加另一个。但是我们在大学里从来没有编写过任何例子。另外,虽然大学没有涉及,但我确实了解界面。但是,我不明白如何使用它们来减少耦合。
添加了指向我上面引用的文章的链接。
编辑2:到目前为止,我现在得到的是以下内容:
public interface IPerson
{
string Name { get; set; }
string PersonAddText(string text);
}
public class Person : IPerson
{
//The code from the person class above
}
我现在如何在主窗口代码中使用它?我猜我应该更换
Person x = new Person();
跟
IPerson x = new Person();
这是正确的吗,如果是这样,我还需要做什么吗?我问的原因是因为我仍然没有看到Visual Studio报告的代码耦合数字有任何减少(事实上,它在后面的主窗口代码上将其增加了1(。
Edit
我很高兴我的回答有所帮助,让我进一步更新它。要将问题用作直接答案,您只需更改以下字段声明:
Person x = new Person();
自
IPerson x = new Person();
您的代码隐藏现在知道接口中指定的属性和方法,并且耦合性要少得多,因为稍后可以将new Person()
换成new Student()
。只要对象实现接口。您的代码隐藏现在应该无需任何必要的更改即可工作。
旁注
我建议考虑延迟加载x
人,并使用名称更易于识别的属性。 注意:这并不能回答您的问题,但这只是一个建议。 :)
private IPerson _CurrentPerson = null;
private IPerson CurrentPerson
{
get
{
if (this._CurrentPerson == null)
{
this._CurrentPerson = new Person();
}
return this._CurrentPerson
}
set
{
this._CurrentPerson = value;
}
}
解耦是指两个或多个代码块不应相互依赖。控制反转是指在运行时绑定对象的耦合,从而允许对象及其实例的更大灵活性,从而减少耦合。控制反转最好与接口结合使用。接口定义了ClassA
将执行MethodX
并具有PropertyY
。我们的主要对象不在乎运行时返回什么对象,只要日志可以完成接口,它就很高兴。
在上面的示例中,您将需要与 person 类进行接口,可能是这样的:
public interface IPerson
{
string Name { get; set; }
string PersonAddText(string text);
}
public class Person : IPerson
{
// your code here
}
然后,在 main 方法调用中,您将使用实现接口 IPerson
的对象实例,而不是显式使用 Person
对象。接口和对象的"连接"可以通过各种不同的库来实现,这将有助于设置依赖项。根据我的经验,我使用过StructureMap和Microsoft的企业库。它们的设置可能有点繁琐,但是一旦设置好了,您就可以做这样的事情了......
public void MainMethod_InInterfaceLayer()
{
// container is an instance of UnityContainer
Person newPerson = container.Resolve<IPerson>();
}
我知道这不是一个完整的答案,但希望它会有所帮助。 :)
假设你有一个IPerson
接口和几个实现(Person
、Student
、Teacher
等(,并且你有一些只需要在IPerson
上运行的代码。
具有:
IPerson x = new Person();
在您的代码中,隐藏会将其强耦合到Person
类。
控制反转通过让依赖项来自外部而不是创建类内部来发挥作用。
这通常是通过使用依赖注入来实现的 - 将IPerson
传递到类中,而不是直接创建它的类。可以通过将实例传递给构造函数(构造函数注入(或作为属性(属性注入(来实现此目的。
服务定位器是另一种获取依赖项而无需对其进行硬编码的方法 - 模式"定位"类型/接口的实例。
如何将依赖项注入类的示例:
public class MyClass
{
IPerson person;
public MyClass(IPerson p)
{
person = p; // injected an instance of IPerson to MyClass
}
// can now use person in any method of the class, or pass it around:
public void MyMethod()
{
string name = person.Name;
}
}
假设你有一个 Person 类,它可以从数据库中加载自身,在他或她去世时进行更改并发送电子邮件。
class Person
{
...
void LoadUsingId(int id);
void HaveDiedWillMail();
void SetFirstName(string name);
...
}
你在这里可以看到的是,这个人实际上在做三件事(至少!
它知道如何与数据库通信以加载自身。它知道如何发送电子邮件。它可以改变自己。
任何代码,理论上如果不实践,应该只负责一件事。要减少这些组件之间的耦合,必须将它们分开。将它们解耦,以便它们可以独立工作。
class Person
{
...
void LoadUsingId(PersonRepository person);
void HaveDiedWillMail(IMailer mailer);
void SetFirstName(string name);
...
}
在这个人为的示例中,人员不知道如何从数据库中加载某些内容。忽略 -加载- 这一事实也是您应该解耦的东西。邮件发送也已分离,因为您告诉Person.HaveDiedWillMail
要使用特定的邮件程序(IMailer mailer
(。
依赖注入、服务容器和此类技术会自动找到您的个人需要/想要的组件才能发挥作用,在解耦之上增加一层,以便更容易将所有单独的部件连接在一起。