The beauty of design patterns learning (e): What appears to be an object-oriented code design, the actual process-oriented?

Common programming style programming paradigm or three, process-oriented programming, object-oriented programming, functional programming, and object-oriented programming is that one of the most mainstream programming paradigm. Now, most programming languages ​​are object-oriented programming language, most software is based on object-oriented programming paradigm to develop this program.

However, in the actual development work, always I thought all code stuffed class, naturally it is carrying out the object-oriented programming. In fact, this understanding is not correct. Sometimes, seemingly from the code object-oriented programming style, in essence it is process-oriented programming style.

What appears to be an object-oriented code design, the actual process-oriented?

When software development using object-oriented programming language, we sometimes write process-oriented style of code. Some are intentional, there is nothing wrong; and some are unintentional whom, will affect the quality of the code.

1. abuse getter, settermethods

It violates the characteristics of object-oriented programming package, equivalent to object-oriented programming style devolved into a process-oriented programming style. By following this example to explain to you this sentence.

public class ShoppingCart {
  private int itemsCount;
  private double totalPrice;
  private List<ShoppingCartItem> items = new ArrayList<>();
  
  public int getItemsCount() {
    return this.itemsCount;
  }
  
  public void setItemsCount(int itemsCount) {
    this.itemsCount = itemsCount;
  }
  
  public double getTotalPrice() {
    return this.totalPrice;
  }
  
  public void setTotalPrice(double totalPrice) {
    this.totalPrice = totalPrice;
  }

  public List<ShoppingCartItem> getItems() {
    return this.items;
  }
  
  public void addItem(ShoppingCartItem item) {
    items.add(item);
    itemsCount++;
    totalPrice += item.getPrice();
  }
  // ...省略其他方法...
}

In this code, ShoppingCartis a simplified shopping cart after class, there are three private ( private) attribute: itemsCount, totalPrice, items. For itemsCount, totalPricetwo properties, we define them getter, settermethods. For itemsproperty, we define its gettermethods and addItem()approach. The code is simple, it is not difficult to understand. Have you ever noticed that this code is the problem?

We first look at two properties before, itemsCountand totalPrice. Although we define them as privateprivate property, but provides publica getter, settermethod, which with these two properties is defined as publicpublic property, no different from the. External can settermodify the value of these two methods optionally property. In addition, any code can be called arbitrary settermethods to re-set itemsCount, totalPricethe value of the property, which will now lead to itemsinconsistent value of the property.

And object-oriented package is defined: by the access control, hide internal data, external interface to access only a limited class provided by modifying internal data. Therefore, it should not be exposed to exposure settermethod, a clear violation of the object-oriented characteristics of the package. Data does not have access control, any code can modify it at will, the code devolved into a process-oriented programming style.

After reading the first two properties, we look at itemsthis property. For itemsthis property, we define its gettermethods and addItem()methods, and it does not define setterthe method. This design looks seemingly no problem, but not really.

For itemsCountand totalPricethese two properties, the definition of a publicthe gettermethod, indeed harmless, after all, getterthe method does not modify the data. However, the itemsproperty is not the same, because the itemsproperty gettermethod returns a Listcollection container. After the caller to get outside the container, the operation is an internal data container, i.e., external code can be modified or itemsdata. For example, like this:

ShoppingCart cart = new ShoppCart();
...
cart.getItems().clear(); // 清空购物车

You might say, functional requirements such empty shopping cart looks reasonable ah, the above code there is nothing wrong ah. You're right, the demand is reasonable, but this code is written, it will lead to itemsCount, totalPrice, itemsinconsistencies three data. We should not be empty cart business logic is exposed to the upper layer code. The correct approach should be, in ShoppingCartthe definition of a class clear()method will clear business logic is encapsulated inside the shopping cart, transparently to the caller to use. ShoppingCartClass clear()specific code implementation of the method is as follows:

public class ShoppingCart {
  // ...省略其他代码...
  public void clear() {
    items.clear();
    itemsCount = 0;
    totalPrice = 0.0;
  }
}

You might also say that I have a demand, need to look at the shopping cart to buy the what, that this time, the ShoppingCartclass has to provide itemsthe property gettermethod, and then how do we do?

If you are familiar with Javathe language, that a solution to this problem is quite simple. We can Javaprovide a Collections.unmodifiableList()way for getterthe method returns a non-modified UnmodifiableListcollection container, and the container class overrides the Listcontainer associated with modifying data method, for example add(), clear()and other methods. Once we call these methods to modify the data, the code will throw UnsupportedOperationExceptionan exception, thus avoiding data container is modified. Specific code implementation shown below.

public class ShoppingCart {
  // ...省略其他代码...
  public List<ShoppingCartItem> getItems() {
    return Collections.unmodifiableList(this.items);
  }
}

public class UnmodifiableList<E> extends UnmodifiableCollection<E>
                          implements List<E> {
  public boolean add(E e) {
    throw new UnsupportedOperationException();
  }
  public void clear() {
    throw new UnsupportedOperationException();
  }
  // ...省略其他代码...
}

ShoppingCart cart = new ShoppingCart();
List<ShoppingCartItem> items = cart.getItems();
items.clear();//抛出UnsupportedOperationException异常

However, such a realization of ideas is still a little problem. Because when the caller through ShoppingCartthe getItems()acquired itemslater, although we can not modify the data in the container, but we can still modify the container for each object ( ShoppingCartItem) data. Sounds a bit around, look at the following few lines of code you will understand.

ShoppingCart cart = new ShoppingCart();
cart.add(new ShoppingCartItem(...));
List<ShoppingCartItem> items = cart.getItems();
ShoppingCartItem item = items.get(0);
item.setPrice(19.0); // 这里修改了item的价格属性

To summarize, in the design implementation class, unless really necessary, otherwise, try not to attribute definition settermethod. In addition, although the gettermethod is relatively setterTo safer, but if it was a collection container (such as the example of Listthe container), but also to prevent the risk of internal data set is modified.

2. The abuse of global variables and methods

In object-oriented programming, common global variables singleton object static member variables, constants, etc., a method common global static method. Singleton object in the global class code only one, so it is equivalent to a global variable. Static member variable classes assigned to the data, is shared by all instances of the object, the global variable corresponding to a certain degree. Constant is a very common and global variables, some of the configuration parameters such as code, typically set to a constant, into a Constantsclass. General Method for operating a static variable or a static external data. You can think of it we used a variety of Utilsclasses, which methods generally defined as a static method, you can not create an object in the case of directly used to use. The static method and data separation method, encapsulation is destroyed, is a typical process-oriented style.

In these global variables and methods just described, the Constantsclass and the Utilsclass most commonly used. Now, we combine the two in almost every software developer will be used in class to look deeply into the pros and cons of global variables and methods.

Let's look at my past involvement in the project, a common Constantsdefinition of class methods.

public class Constants {
  public static final String MYSQL_ADDR_KEY = "mysql_addr";
  public static final String MYSQL_DB_NAME_KEY = "db_name";
  public static final String MYSQL_USERNAME_KEY = "mysql_username";
  public static final String MYSQL_PASSWORD_KEY = "mysql_password";
  
  public static final String REDIS_DEFAULT_ADDR = "192.168.7.2:7234";
  public static final int REDIS_DEFAULT_MAX_TOTAL = 50;
  public static final int REDIS_DEFAULT_MAX_IDLE = 50;
  public static final int REDIS_DEFAULT_MIN_IDLE = 20;
  public static final String REDIS_DEFAULT_KEY_PREFIX = "rt:";
  
  // ...省略更多的常量定义...
}

In this code, we used the program in all constants are concentrated into this Constantscategory. However, the definition of such a large and Constantsclass, not a very good design ideas. Why do you say? The main reasons are as follows.

First of all, this design will affect the maintainability of the code.

If there is involved in the development project with a lot of engineers in the development process, this class may have to involve changes, such as adding a constant to the class, the class that will become more and more, hundreds of thousands of rows it is possible to find a constant modification will become more time-consuming, but also increase the probability of collision submit code.

Secondly, this design will increase the compile time code.

When Constantsthe time constant defined class contains many of this type of code will be dependent on a lot. That each modification Constantsclass, it can lead to dependence class file recompilation, so it will waste a lot of unnecessary compilation time. Do not underestimate the time it takes to compile, for a very large project, the time it takes to compile a project could be minutes or even tens of minutes. And we in the development process, each time you run the unit tests will trigger a process of compilation, the compilation time is likely to affect our development efficiency.

Finally, this design will also affect the reusability of code.

If we want another project, reuse a class developed in this project, and this in turn depends on the class Constantscategory. Even if this kind depend on only Constantsa small portion of the constants in the class, we still need to put the whole Constantsclass together also introduced, also introduced many unrelated constants into the new project.

How that improved Constantsdesign class it? There are two ideas can learn.

The first is the Constantsclass for the dismantling of a single function more multiple classes, such as with MySQLrelated constants configuration, we put MysqlConstantsthe class; with Redisrelated constants configuration, we put RedisConstantsclass. Of course, there is a feel better design ideas, it is not solely the design Constantsconstants class, but the class which uses a constant, we put this constant definition of this class. For example, the RedisConfigclass uses Redisconfiguration-related constants, then we will direct these constants are defined in RedisConfig, so that also increases the reusability of code and cohesion of the class design.

Finished Constantsclass, let's talk about Utilsclass. First of all, like to ask you a question, why do we need Utilsthe class? UtilsWhat is the meaning of class existence?

When talking about object-oriented features, talked about inheritance can achieve code reuse. Using inheritance characteristics, we have the same properties and methods, extracted, defined in the parent class. Subclasses multiplexing properties and methods of the parent class, the purpose of code reuse. However, sometimes, from the business meaning, Aclass and the Bclass does not necessarily have inherited, such as Crawlerclasses and PageAnalyzerclasses that have used the URLfunction and stitching division, but does not have inheritance (neither parent-child relationship, nor is it brotherhood). Only for code reuse, a blunt abstract superclass out will affect the readability of the code. If you are not familiar with the design ideas behind colleagues found that Crawlerclasses and PageAnalyzerclass inheritance with a parent, but the parent class definition is URLrelated operations, will find this code is written somehow, can not understand.

Since inheritance can not solve this problem, we can define a new class that implements the URLstitching and method of segmentation. The stitching and split two ways, without sharing any data, so the new class does not define any attribute, this time, we can define it as containing only static methods of Utilsclass a.

Indeed, contains only static methods have no properties of Utilsthe class, is the programming style thoroughly process-oriented. This does not mean we have to eliminate the use of Utilsclass a. In fact, just talking about Utilsthe purpose of the existence of the class point of view, it is still quite useful software development and code reuse can solve the problem. So, here it is not to say completely unable to use Utilsthe class, but that, to avoid abuse, do not feel free to go without thinking defined Utilsclass.

Defined Utilsbefore the class, you have to ask yourself, do you really need a separate definition of such a Utilsclass it? If you can Utilsdefine certain methods in the class to other classes as well? If, after answering these questions, do you still feel the need to define such a Utilsclass, it would be bold to define it now. Because even in object-oriented programming, we are not entirely exclusive process-oriented style of code. As long as it can write good code we contribute, we can reasonably go use.

In addition, analog Constantsclass design, we design Utilsclass, the best it can be refined for different functions, different design Utilscategories, such as FileUtils, IOUtils, StringUtils, UrlUtilsand so on, do not be too large and a design Utilsclass.

3. The method of separation and definition data class

The last object programming process, common process-oriented style code-oriented. That is, data is defined in a class, the method is defined in another class.

The conventional MVCstructure is divided into Modellayers, Controllerlayer, Viewlayer of the three layers. However, after the end of the separator before and after doing, the development of three-layer structure at the rear, will be slightly adjusted, is divided into Controllerlayers, Servicelayer, Repositorylayer. ControllerLayer is responsible for exposing interfaces to the distal call Servicelayer is responsible for the core business logic Repositorylayer is responsible for reading and writing data. In each layer, we will define the corresponding VO( ),View Object ( ), . In general, , , the only definition data does not define the method, all of the business logic of these operations are defined in the data corresponding to the class, the class, the class. This is the programming style typical process-oriented.BOBusiness ObjectEntityVOBOEntityControllerServiceRepository

In fact, this development model is called pattern-based development model of anemia , but also we are now very common kind of Webdevelopment model project.

In object-oriented programming, process-oriented style Why is easy to write code?

You can think about, in life, you to complete a task, you usually think, what to do first, what to do after, how to perform a series of operations sequentially step by step, and finally complete the task. Process-oriented programming style is precisely in line with people's way of thinking of this process. The object-oriented programming style just the opposite. It is a bottom-up way of thinking self. It is not in accordance with the implementation process to go break down the task, but the task will be translated into one of a small module (ie class), the interaction between design class, the last class will be assembled in accordance with the process, to complete the task. In the last lesson we talked about, this path of thinking more suitable for the development of complex programs, but not particularly consistent with human thinking habits.

In addition, object-oriented programming harder than process-oriented programming. In object-oriented programming, class design is still very tricky, very need some design experience. You need to think about how to package the appropriate data and methods to a class, how to design the relationship between classes, how to design interactive design, and many other issues between classes.

So, based on these two reasons, a lot of engineers in the development process, but also tend to use less need for mindless way to achieve demands, it will not help the process-oriented style of the code written in the.

Process-oriented programming and process-oriented programming language really useless yet?

We have mentioned earlier, if we develop a small program or a data processing code related to algorithm-based, supplemented by data, that process of scripted programming style is more suitable for some oriented. Of course, the useless process-oriented programming more than that. In fact, the process-oriented programming is the basis for object-oriented programming, process-oriented programming can not do without the foundation of object-oriented programming. Why do you say that? We think about it, realization logic of each method in the class, not that process-oriented style of code?

In addition, object-oriented and process-oriented two programming style, not black and white, completely opposite. In the software with object-oriented programming language developed, the code process-oriented style is not uncommon, even in some standard development libraries (such as JDK, , Apache Commons),Google Guava there are a lot of process-oriented style of code.

Regardless of process-oriented or object-oriented using what style to write code, our ultimate goal is to write and easy to maintain, easy to read, easy reuse, easy to expand high-quality code. As long as we can avoid some of the disadvantages of process-oriented programming style, good control of its side effects, within the control range of work for us, we can not evade large process-oriented style of writing code in an object-oriented programming.

RECAP

1. abuse getter, settermethods

When designing the implementation class, unless really necessary, or try not to attribute definition settermethod. In addition, although the gettermethod is relatively setterTo safer, but if the return is a collection container, it should also guard against the risk of internal data collection is modified.

2. Constantsclass, Utilsdesign issues category

For both types of design, we can try to do the duties of a single, defined some refinement of subcategories, such as RedisConstants, FileUtilsrather than defining a large and Constantsclass, Utilsclass. In addition, if the properties and methods of these classes can divided merged into other business class, it is most desirable that, can greatly improve the cohesion and the class code reusability.

  1. Model-based development model of anemia

We talked about why this development model is thoroughly process-oriented programming style. This is because the data and the operations are defined separately VO/BO/Entityand Controler/Service/Repositoryin.

Reference: What is object-oriented code is designed to look like the actual process is facing?

This article from the blog article multiple platforms OpenWrite release!
For more information, please click on my blog Mu Chen

Guess you like

Origin www.cnblogs.com/muchen-li/p/11960323.html