preface
We can do development without design patterns. But why design patterns? Makes you look great. Yeah, that’s one of them. Make your code hierarchical, readable, and easy to maintain. Give you more time to fish and paddle like ME.
Maybe some people say that I can do one class or method, you did seven or eight things. Of course, there are considerations to use design patterns. Design patterns are also not recommended for simple, stable businesses. Design patterns are mostly used in complex and changeable businesses or scenarios that require more adaptability and scalability. Don’t design patterns for the sake of designing patterns.
Let’s take a look at some of the principles of design patterns in practice.
1. Open and close principle
public class Seller {
public BigDecimal sellCar(Car car) {
returncar.getPrice(); }}Copy the code
A salesman in a 4S shop is selling cars. Suddenly the boss made a promotion: in the Double eleven to carry out a discount activity. Is it feasible to add a calculation to the sellCar method? This is bound to affect the whole business, leading to discounts on all cars. No, no! What about operating in Car? And then you change and change! Results All kinds of logical flow judgment. To achieve the business requirements. If subsequent discounts end or upgrades are made, you’ll have to make all sorts of changes. You find that a discount leaves your code unrecognizable and bloated. The above mentioned complex and changeable business can be solved by using design patterns.
One of the most important principles of design patterns is the open close principle. That is, a software model entity such as classes, modules, and functions should be open for extension and closed for modification. That is, we need to abstract out the business behavior, use abstraction to build. Concrete business is solved through abstract implementation. So let’s make a DiscountCar extends Car. Thus whatever specific implementation sellCar is, the specific logic is executed. Previous logic is not affected, and changes to the original code do not affect other logic. Ensure interface reliability and stability. As follows:
public class DiscountCar extends Car{
private BigDecimal price;
private BigDecimal discount;
@Override
public BigDecimal getPrice() {
returnprice.multiply(discount); }}Copy the code
2, dependence inversion principle
Take the example above. After a series of discount activities 4S shop business is booming. The boss suddenly wanted to expand the perimeter and squeeze sales. Let them sell their cars with glass water and antifreeze. This requirement, of course, was thrown to the helpless and miserable programmer. SellCar is too specific to meet the needs. In many cases you will add a way to sell glass water and antifreeze. What if they sell more rice and even buy egg cakes? You can’t just keep adding methods. We need to think about that. We can abstract all the situations in which things are sold. We then abstract the item we sell into an abstract concept (Java’s counterpart is the interface, abstracting the act of selling into the sell method:
public interface Any {
String getName();
BigDecimal getPrice();
}
public class Seller {
public BigDecimal sell(Any any) {
returnany.getPrice(); }}Copy the code
This way you can handle whatever the boss sells in the future, just focus on the implementation of Any.
3. Principle of single responsibility
After selling a section of things, THE 4S shop found that it did not attract customers. Suddenly the more flexible boss remembered a line in the movie: Shaolin kung fu plus singing and dancing have no head? Yeah, well, what if you guys in sales did something like sing, dance, Rap, but not basketball so you don’t break the car Windows. But people are not the same, some people can only sing, some people can only jump, some people may sing and jump Rap will even basketball are very slip. So in order to fit so many situations, we have to separate each skill out and mix it up for different people.
public class Seller implements Sing, Jump, Rap {
public BigDecimal sell(Any any) {
return any.doSell();
}
@Override
public void sing() {
System.out.println("seller sing ");
}
@Override
public void jump() {
System.out.println("seller jumping ");
}
@Override
public void rap() {
System.out.println("seller raping "); }}Copy the code
But be careful to be moderate and break it down by business. Otherwise, there will be too many interfaces that will increase the difficulty of development and the complexity of the code.
Demeter’s Rule
After working on the new sales method for some time, the boss wanted to see how his bad idea worked. So called a sales let him provide a report to see. So how can a programmer implement the boss to view the report function, most likely someone will write:
public class Boss {
private Seller seller;
private Report report;
public void read() { seller.apply(report); }}Copy the code
At first glance the function is implemented, but a closer look will show that the logic is wrong. What’s wrong? The boss already holds the report, if the boss already knows your performance still ask you why? This logic must be wrong! That is, bosses rely directly on reports; The Report should not be handled directly by the Boss, but controlled by the Seller.
public class Boss {
private Seller seller;
public void read(){
seller.apply();
}
}
public class Seller {
private Report report;
public void apply(){ report.show(); }}Copy the code
This maximization isolates the relationships between classes. Reduces coupling between classes. Demeter’s rule is also known as the least know principle.
5. Interface isolation principle
With multiple specialized interfaces rather than a single master interface, a client should not rely on interfaces it does not need. The dependencies of a class to a class should be based on the smallest interface.
Create a single interface instead of a large and bloated interface and try to refine the interface as few methods as possible. Pay attention to moderation. Moderation. Can’t abuse
Like the rap above, separation is best.
6. Richter’s substitution principle
This is mainly concerned with class inheritance. A more formal definition: If for every object o1 of type S, there is object O2 of type T, such that the behavior of all programs P defined by T does not change when all objects O1 are replaced by O2, then type S is a subtype of type T.
In the eyes of 4S shop owners, as long as the new guy can sell cars like an experienced salesman on the sales position, he is a qualified salesman. This definition feels like a famous saying: it doesn’t matter if you’re black or white, the cat that catches mice is a good cat.
In a sense, the Richter substitution has the following contract:
1. A subclass must fully implement the methods of its parent class. A subclass can replace a parent class wherever it appears.
2. Subclasses can have their own personality definitions. Richter’s substitution principle can be used head on, but not the other way around. Where subclasses appear, superclasses are not necessarily competent. Subclasses generally have more personality than their parents.
3. Input parameters can be amplified when overwriting or implementing methods of the parent class. If the 4S shop owner provides a discount of up to 90% on the basic car price, there is no problem with a 5% discount on sales, and the boss will certainly tell you about the 20% discount.
4. The output can be reduced when overwriting or implementing methods of the parent class. The same 15W could only be sold to the customer as a beggar version, but changed the sales result to give a flagship version. I’m afraid I can’t pass the probation period.
7. Principle of synthesis/reuse
It requires that in software reuse, we should first use association relation such as combination or aggregation, and then consider using inheritance relation.
If inheritance is to be used, the Richter substitution principle must be strictly followed. The principle of composite reuse and the Principle of Richter’s substitution complement each other.
conclusion
These seven design principles are the principles that software design patterns must follow as far as possible, and each principle requires different emphases. Among them, the open and closed principle is the general principle, it tells us to be open to expansion, to modify closed; Richter’s substitution tells us not to break the inheritance system; The dependency inversion principle tells us to program for interfaces; The single responsibility principle tells us to implement a class with a single responsibility; The principle of interface isolation tells us to keep interfaces simple and simple when designing them. Demeter’s rule tells us to reduce coupling; The principle of composite reuse tells us to use composite or aggregate relation reuse in preference to inheritance relation reuse. In practice, you can use design patterns based on the business, but it’s important not to get bogged down by these rules.
The last
Welcome to pay attention to my public number [programmer chasing wind], the article will be updated in it, sorting out the data will be placed in it.