如何实践OOP设计的SOLID原理? [英] How to practice SOLID principle of OOP design?

查看:285
本文介绍了如何实践OOP设计的SOLID原理?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很了解SOLID原理,但我明白了。我的主要问题是很难设计我的课程以遵循SOLID特别是依赖性反转。有时很容易将整个逻辑写入程序模式,而不是使用SOLID。



例如:



假设我们正在创建一个考勤监控系统,我们有逻辑(或程序)扫描员工指纹,获取ID,确定是否有效,确定他在什么时间,将登录信息写入数据库,并显示是否成功。



很容易以一个if else,循环和开关的方式以程序方式写入。但是,将来我会受到代码债务的困扰。



如果我们在这里申请SOLID原则。我知道我们需要一些类似'AttendanceServiceClass'的对象,例如'scanEmployeeID()','processthislogin()'或'isItsucessful()')。而且我知道这个类具有对repository,userinfo和其他对象的依赖。



基本上我的问题是分析类的设计及其依赖性



什么是一步一步分析课程设计的方法?



对于我的英语,我很抱歉

解决方案



有时很容易将整个逻辑写入程序模式而不是使用SOLID



我不能同意更多,我们的程序员更容易处理代码在程序模式。这使得OOP对于习惯于程序化编程的程序员来说很困难。



然而,我发现更容易编写通用接口和消费者,而不是将设计的接口设计为较小的模块。这是一种 Test First Development - >红色,绿色,重构练习。 (请注意,如果您想实现整齐的设计,请考虑遵循TDD,而不是本指南。本指南只是TDD的一小部分。 strong>



假设我们要创建 ServiceAttendance 来执行 scanEmployeeID 。我们将有一个界面(请注意C#命名的例子):

  public interface IServiceAttendance {
bool ScanEmployeeId ();
}

请注意,我决定返回bool而不是void的方法来确定成功/故障操作。请注意,下面的消费者示例不实现任何DI,因为我只想显示如何消费。然后在消费者中,我们可以有:

  public void ConsumeServiceAttendance(){
IServiceAttendance attendance = Resolve< IServiceAttendance> ();
if(attendance.ScanEmployeeId()){
// do something
}
}

消费者总结说。现在我们转向实施。说你可以使用过程编程来开发它,并获得单片代码块。您可以使用pseu-like语句来表示实现。

  public class ServiceAttendance:IServiceAttendance {
public bool ScanEmployeeId() {
bool isEmpValid = false;
// 1扫描员工ID
// 2验证登录
// 3如果有效,创建登录会话
// 4通知用户
返回isEmpValid;
}
}

现在我们有4个步骤要完成这个操作。我的校长是,在一个方法中不要做3个以上的外观过程,所以我可以简单地重构3和4到一个过程。现在我们有

  public class ServiceAttendance:IServiceAttendance {
public bool ScanEmployeeId(){
bool isEmpValid =假;
// 1扫描员工ID
// 2验证登录
// 3如果有效,创建登录会话并通知用户
return isEmpValid;
}
}

这里,我们有3个主要操作。我们可以通过分解操作来分析是否需要创建一个较小的模块。说我们想打破第二个操作。我们可以得到:

  // 2验证登录
// 2.1检查员工ID是否符合格式策略
// 2.2检查仓库中是否存在员工ID
// 2.3检查员工ID是否有效访问模块

故障操作本身足够明显,可将第二个模块拆分成另一个较小的模块。对于 2.2 2.3 ,我们需要一个较小的模块来注入。因为它需要依赖于存储库,所以需要注入。同样的情况适用于操作步骤 1扫描员工ID ,因为它将需要依赖指纹扫描器,因此扫描器处理程序必须以分离的模块实现。



我们可以随时细分操作,我们可以在 2.1 中执行操作:

  // 2.1检查员工ID是否匹配格式策略
// 2.1.1员工ID必须匹配长度
// 2.1.2员工ID必须有格式emp #####

现在我不确定 2.1 .1 2.1.2 需要细分为2个独立的模块,由您决定。现在我们得到了接口,然后我们可以开始实现。期待在验证过程中抛出异常,否则您将需要传递自定义类来处理错误消息。


I'm new to SOLID principle but I understand it. My main problem is having a hard time designing my classes to follow the SOLID specially the Dependency Inversion. Sometimes it's easy to write the whole logic into procedural pattern rather than to use SOLID.

For example:

Let's say that we are creating an Attendance Monitoring System, and we have logic(or procedure) that scan the employee fingerprint, get it's ID, determine whether or not it's valid or not, determine what time he was in, write the login info to the database, and show if it's successful or not.

It is easy to write this in a procedural manner with a bunch of 'if else', loop and switch. But in future I'm gonna suffer the 'code debt'.

If we applying SOLID principle here. I know that we need to have a some kind of object like 'AttendanceServiceClass' that has a method like 'scanEmployeeID()', 'processthislogin()' or 'isItsucessful()'. And I know that this class has a dependency to a repository, userinfo, and other objects.

Basically my problem is analyzing about the design of the class and its dependencies

What is the step by step way of analyzing the design of your class?

sorry for my English.

解决方案

Sometimes it's easy to write the whole logic into procedural pattern rather than to use SOLID

I cannot agree more, it is easier for us programmer to handle code in procedural pattern. This makes OOP hard for programmer who accustomed to procedural programming.

However I found it easier to write the general interface and consumer first rather than breaking the interface designed to smaller modules. This is, a kind of Test First Development -> Red, green, refactor practice. (please note that, if you want to achieve the neat design, consider following TDD instead this guide. This guide is just a small section of doing TDD)

Say that we want to create the ServiceAttendance to do scanEmployeeID. We will has interface like (please notice the example is in C# naming):

public interface IServiceAttendance{
    bool ScanEmployeeId();
}

Please noted that I decide the method to return bool instead of void to determine success/failure operation. Please notice the consumer example below does not implement any DI because I just want to show how to consume it. Then in the consumer, we can have:

public void ConsumeServiceAttendance(){
    IServiceAttendance attendance = Resolve<IServiceAttendance>();
    if(attendance.ScanEmployeeId()){
        // do something
    }
}

This concludes the consumer. Now we move to implementation. Say that you can develop it using procedural programming and got the monolithic code block. You can state the implementation with pseu-like statement.

public class ServiceAttendance : IServiceAttendance{
    public bool ScanEmployeeId(){
        bool isEmpValid = false;
        // 1 scan the employee id
        // 2 validate the login
        // 3 if valid, create the login session
        // 4 notify the user
        return isEmpValid;
    }
}

Now we have 4 steps to be done in this one operation. My principal is, not to do over 3 facade process in one method so I can simply refactor the 3 and 4 to one process. Now we have

public class ServiceAttendance : IServiceAttendance{
    public bool ScanEmployeeId(){
        bool isEmpValid = false;
        // 1 scan the employee id
        // 2 validate the login
        // 3 if valid, create the login session and notify the user
        return isEmpValid;
    }
}

This, we have 3 main operation. We can analyze whether we need to create a smaller module or not by breaking down the operation. Say we want to break the second operation. We can get:

// 2 validate the login
// 2.1 check if employee id matches the format policy
// 2.2 check if employee id exists in repository
// 2.3 check if employee id valid to access the module

The breakdown operation itself is obvious enough to break the second module into another smaller module. For 2.2 and 2.3, we need a smaller module to be injected. Simply because it will need dependency to repository, thus need to be injected. The same case apply for operation step 1 scan the employee id, because it will need dependency to fingerprint scanner, so the scanner handler must be implemented in separated module.

We can always breakdown the operation, as we can do it in 2.1:

// 2.1 check if employee id matches the format policy
// 2.1.1 employee id must match the length
// 2.1.2 employee id must has format emp#####

Now I am unsure if 2.1.1 and 2.1.2 need to be broken down into 2 separated modules, it is up to you to decide. And now we got the interfaces, then we can start the implementation. Expect to throw exceptions during validation or you will need to pass custom class to handle error messages.

这篇关于如何实践OOP设计的SOLID原理?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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