. NET reconstruction (Design and reconstruction of type codes)

Source: Internet
Author: User

Reading directory:

  • 1. Introduction

  • 2. the type code is replaced by the logical behavior enumeration, constant, and Entity subclass of the object)

  • 3. the type code is abstracted from the logical behavior of the affected object, which is solved by polymorphism)

  • 4. You cannot directly abstract the type code and use the policy mode to solve the problem)

1. Introduction

When it comes to type codes, we will be very impressed. In a certain Entity, there will be more or less one or two types of codes to indicate which level the current Entity belongs to in an abstract angle, for example, inEmployeeEntityBasically, there is a Sex attribute indicating gender, and the Sex attribute is stored in a Sex field, which is a typical type code element; the Sex type code attribute is used to indicate that when the entity is classified from the abstract perspective of gender, there are two types of summarized entities: male and female );

In any logic place where the Sex type code property is used, different logic branches may be implemented because of its different values.EmployeeCollectionEntityDefine a method in the object to return all the EmployeeEntity of the specified type. We simply assume that there must be a logic inside the EmployeeeCollectionEntity to judge based on the parameters of the current method, then call different methods to return the EmployeeEntity of all execution parameters in the current set;

The above is only a simple application scenario, but it is sufficient to briefly describe the meaning and application scenarios of the type code, next we will analyze the use of three types of codes and how to reconstruct the design for this simple example mentioned above; what should we do when the type code is not used by any logic but is provided to a simple external identifier? What should we do when the type code directly affects the internal behavior logic of the entity; what should we do when the type code affects the internal logic of the entity, but we cannot extract it directly to abstract it;

We will carry out the following detailed analysis with these three simple questions;

2) The type code is replaced by the logical behavior enumeration, constant, and Entity subclass of the object)

The problem is well handled without affecting the internal logic of the object. Since the internal logic of the object is not affected, its representation is at least irrelevant to the internal logic of the object; at this time, we can follow the principle of OO for its design. If we use a simple number to represent the status of the type code, then we can design or reconstruct it in three ways;

There is a small problem here: if we are performing a partial DomainModel internal reconstruction, we will have a lot of work and need a good unit test to support it; however, if we are currently designing an Entity problem, it will be very simple;

Next we will use the simple scenario mentioned in section 1 above as the domain model demonstrated in this section;

EmployeeEntity code:

public class EmployeeEntity{    private int sex;    public int Sex    {        get { return sex; }        set { sex = value; }    }}


Code for EmployeeCollectionEntity:

public class EmployeeCollectionEntity : List<EmployeeEntity>{    public IEnumerable<EmployeeEntity> GetEntityBySex(int sex)    {        return from item in this where item.Sex == sex select item;    }}

Test Code. For convenience, I didn't specifically create the UnitTests project, but simply used the console program to simulate it:

EmployeeCollectionEntity empCollection = new EmployeeCollectionEntity()            {                new EmployeeEntity() { Sex = 1 },                new EmployeeEntity() { Sex = 2 },                new EmployeeEntity() { Sex = 2 }            };            var resultList = empCollection.GetEntityBySex(2);            if (resultList.Count() == 2 && resultList.ToList()[0].Sex == 2 && resultList.ToList()[1].Sex==2)                Console.WriteLine("is ok");            Console.ReadLine();

The above code is very simple. An Employee is used to represent the Employee entity, and the Employee collectionentity is used to represent the Employee entity set, which is used to encapsulate a set of Empoyee sets containing the business logic. Currently, there is a method GetEntityBySex (int sex ), it is used to obtain all EmpoyeeEntity that meets the conditions in the set based on the gender type code. In the unit test code, we use 1 to indicate female and 2 to indicate male, the unit test correctly queries two groups of male EmployeeEntity entities through the test code;

Below we will gradually use three methods to redesign this type of business scenario, also known as restructuring;

1. Replace the type code number with the enumerated type;

EmployeeEntity code:

public class EmployeeEntity{    public enum EmployeeSex    {        Male,        Female    }    private EmployeeSex sex;    public EmployeeSex Sex    {        get { return sex; }        set { sex = value; }    }}

Code for EmployeeCollectionEntity:

public class EmployeeCollectionEntity : List<EmployeeEntity>{    public IEnumerable<EmployeeEntity> GetEntityBySex(EmployeeEntity.EmployeeSex sex)    {        return from item in this where item.Sex == sex select item;    }}

Test code:

EmployeeCollectionEntity empCollection = new EmployeeCollectionEntity()           {               new EmployeeEntity() { Sex = EmployeeEntity.EmployeeSex.Female },               new EmployeeEntity() { Sex = EmployeeEntity.EmployeeSex.Male },               new EmployeeEntity() { Sex = EmployeeEntity.EmployeeSex.Male }           };           var resultList = empCollection.GetEntityBySex(EmployeeEntity.EmployeeSex.Male);           if (resultList.Count() == 2 && resultList.ToList()[0].Sex == EmployeeEntity.EmployeeSex.Male &&               resultList.ToList()[1].Sex == EmployeeEntity.EmployeeSex.Male)               Console.WriteLine("is ok");           Console.ReadLine();

By using enumeration, we can use the benefits of OOD well, so that the Code will not be filled with this mess of magic numbers;

Second, use constants instead of type codes;

In fact, when constants are used to replace type codes, a common business scenario is when interacting with remote terminals, because when we translate Entity into a certain transmission object, we need to express its attributes in the form of a string. For example, if we want to send an employee ID to a message queue, then the backend program of the Message Queue needs to directly insert it into the database. At this time, our DomainModel does not exist in the backend program of the message queue, that is, it has not been mapped to the database, the attribute type code here will be an equivalent string to the database; so if we choose to use enumeration or constant to replace the type code, the criterion is whether the type code needs to be persistent, that is, stringization;

EmployeeEntity code:

public class EmployeeEntity{    public const int Male = 2;    public const int Female = 2;    private int sex;    public int Sex    {        get { return sex; }        set { sex = value; }    }}

Code for EmployeeCollectionEntity:

public IEnumerable<EmployeeEntity> GetEntityBySex(int sex){    return from item in this where item.Sex == sex select item;}

Test code:

EmployeeCollectionEntity empCollection = new EmployeeCollectionEntity()            {                new EmployeeEntity() { Sex = EmployeeEntity.Female},                new EmployeeEntity() { Sex = EmployeeEntity.Male },                new EmployeeEntity() { Sex = EmployeeEntity.Male}            };            var resultList = empCollection.GetEntityBySex(EmployeeEntity.Male);            if (resultList.Count() == 2 && resultList.ToList()[0].Sex == EmployeeEntity.Male &&                resultList.ToList()[1].Sex == EmployeeEntity.Male)                Console.WriteLine("is ok");            Console.ReadLine();

Using constants instead of type codes means that only numbers can be used to represent IEnumerable <EmployeeEntity> GetEntityBySex (int age) on the interface, and then we will directly use the constant empCollection when calling. getEntityBySex (EmployeeEntity. male );

Third, use the Entity subclass to replace the type code;

If the employee ID has an inheritance system in the Sex perspective, we can use the Entity subclass to solve the problem, gender Male and Female inherit their respective systems from the EmployeeEntity. MaleEmployeeEntity is male and FemaleEmployeeEntity is female. Of course, in real scenarios, this small gender will not be used as an independent inheritance system;

EmployeeEntity code:

public abstract class EmployeeEntity{    public abstract bool IsFemale { get; }    public abstract bool IsMale { get; }}

At this time, the Employee ID is no longer a real Employee;

MaleEmployeeEntity code:

public class MaleEmployeeEntity : EmployeeEntity{    public override bool IsFemale    {        get { return false; }    }    public override bool IsMale    {        get { return true; }    }}

Code for FemaleEmployeeEntity:

public class FemaleEmployeeEntity : EmployeeEntity{    public override bool IsFemale    {        get { return true; }    }    public override bool IsMale    {        get { return false; }    }}

Code for EmployeeCollectionEntity:

public class EmployeeCollectionEntity : List<EmployeeEntity>   {       public IEnumerable<EmployeeEntity> FemaleEmployeeList       {           get           {               return from item in this where item.IsFemale select item;           }       }       public IEnumerable<EmployeeEntity> MaleEmployeeList       {           get           {               return from item in this where item.IsMale select item;           }       }   }

Test code:

EmployeeCollectionEntity empCollection = new EmployeeCollectionEntity()           {               new FemaleEmployeeEntity(),               new MaleEmployeeEntity() ,               new MaleEmployeeEntity()           };           var resultList = empCollection.MaleEmployeeList;           if (resultList.Count() == 2 && resultList.ToList()[0].IsMale && resultList.ToList()[1].IsMale)               Console.WriteLine("is ok");           Console.ReadLine();

Since there is no type code, there will be no interface for getting data based on parameters, so we will slightly change it and split the parameters into specific attributes to directly return the data set;

3] The type code is abstracted from the logical behavior of the affected object, which is solved by polymorphism)

The methods mentioned in section 2 are the design methods when the type code does not affect the specific business logic of the program, however, once the Type Code directly affects the specific business logic in our DomainModel, I need to extract the type code and abstract the inheritance system, then, the specific logic and the type code inheritance system are taken. This is also the responsibility-oriented design in the object-oriented system, and the behavior should be put into the most common object called by it as much as possible;

Assume that there is a set of OrderCollection orders in the EmployeeEntity. Now we need to get the OrderCollection to be delivered based on the different levels of the EmployeeEntity EmployeeLevel to get GetDistributionOrders, here, there is a business rule that different levels have different conditions for each delivery order. The specific conditions are related to the current EmployeeLevel, in this case, we need to encapsulate level-related logic into EmployeeLevel;

Figure 1:

650) this. length = 650; "src =" http://www.bkjia.com/uploads/allimg/131229/12394Q913-0.jpg "title =" 1.jpg" width = "700" height = "290" border = "1" hspace = "1" vspace = "1" style = "width: 700px; height: 290px; "alt =" 141116287.jpg"/>

Order code:

public class Order{    public DateTime SubmitDtime { get; set; }}

OrderCollection code:

public class OrderCollection : List<Order>{}

EmployeeEntity code:

Public class EmployeeEntity {public EmployeeLevel Level {get; set;} public OrderCollection AllDistributeionOrders {get; set;} public OrderCollection GetDistributionOrders () {return Level. getDistributionOrders (); // call method after pushing the logic to the type code ;}}

EmployeeLevel code:

Public abstract class EmployeeLevel {public EmployeeEntity employee; public abstract OrderCollection GetDistributionOrders ();} public class Normal: EmployeeLevel {public override OrderCollection GetDistributionOrders () {if (employee. allDistributeionOrders = null & employee. allDistributeionOrders. count = 0) return null; var orders = from order in employee. allDistributeionOrders where order. submitDtime <= DateTime. now. addDays (-5) // Normal delays delivery for five days select order; if (orders. toList (). count = 0) return null; OrderCollection result = new OrderCollection (); orders. toList (). forEach (order => {result. add (order) ;}); return result ;}} public class Super: EmployeeLevel {public override OrderCollection GetDistributionOrders () {if (employee. allDistributeionOrders = null & employee. allDistributeionOrders. count = 0) return null; var orders = from order in employee. allDistributeionOrders where order. submitDtime <= DateTime. now. addDays (-1) // Super delays delivery by one day select order; if (orders. toList (). count = 0) return null; OrderCollection result = new OrderCollection (); orders. toList (). forEach (order => {result. add (order) ;}); return result ;}}

Test code:

OrderCollection orderColl = new OrderCollection();           orderColl.Add(new Order() { SubmitDtime = DateTime.Now.AddDays(-2) });           orderColl.Add(new Order() { SubmitDtime = DateTime.Now.AddDays(-7) });           EmployeeEntity employee = new EmployeeEntity()           {               AllDistributeionOrders = orderColl           };           EmployeeLevel level = new Super() { employee = employee };           employee.Level = level;           var result = employee.GetDistributionOrders();           if (result.Count == 2)               Console.WriteLine("Is ok");           Console.ReadLine();

We have defined two EmployeeLevel. One is Normal, that is, Normal. The condition for delivery is that delivery must be postponed for five days, and the other is Super, his delivery was postponed for only one day. If we didn't abstract the Type Code for design, we would face the judgment of a condition branch, when other levels need to be added later, we will gradually fall into the quarary of determining branches;

4] The Type Code cannot be directly abstracted and solved using the Policy Mode)

In section 3, we can very well abstract the type code, but if we are faced with a refactoring project, it is difficult for us to directly modify a large area of code, you can only balance the design of the type code into a method of strategic significance. Different types of codes correspond to different policy schemes;

Let's take the example in Section 3 as an example. Now, if we are refactoring an EmployeeEntity that uses int directly as the type code, we cannot directly modify the internal logic of the EmployeeEntity, instead, we need to map different types of codes to the policy methods by introducing the policy factory;

Figure 2:

650) this. length = 650; "src =" http://www.bkjia.com/uploads/allimg/131229/12394W951-1.jpg "title =" 2.jpg" width = "700" height = "345" border = "1" hspace = "0" vspace = "0" style = "width: 700px; height: 345px; "alt =" 141254800.jpg"/>

This section does not provide sample code because the code is relatively simple. The above UML class diagram shows the code structure;


Author:Wang qingpei

Source:Http://wangqingpei557.blog.51cto.com/

The copyright of this article is shared by the author and BKJIA. You are welcome to repost this article. However, you must retain this statement without the author's consent and provide the original article connection clearly on the article page. Otherwise, you will be entitled to pursue legal liability.



This article is from the pattern driven the world blog, please be sure to keep this source http://wangqingpei557.blog.51cto.com/1009349/1327850

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.