Hello, everyone. Today I’m here to talk about the protocol model.

Specification Pattern in English is Specification Pattern. Specification here is actually an ideographic translation. The literal translation of Specification means requirement, technical description and clear meaning. Just by looking at the name, people are probably confused and have no idea what the design pattern is going to look like. This is also a common fault of the design model, is more obscure connotation, it is difficult to generalize through the name.

Let’s start with a brief description of what the specification means. It simply means to separate the code logic from the business rules in the code. In this way, we can freely modify and combine the two parts without affecting the overall situation.

Now, I know you’re probably not going to understand this, but let’s just do a quick example.

For example

We all know QQ has all kinds of diamond members, what green diamond, pink diamond and so on. Each member has some special benefits. Let’s say we’ve developed a new feature that we want to provide to users who own both green and pink diamonds.

We can implement this logic very easily, just need a judgment condition.

def is_satisfied(user):

    return user.isGreenAuth() and user.isPinkAuth()

Copy the code

The problem is that the logic is dead, and over time, if the code is handed over to someone else to maintain, the person who inherited it will probably be confused. I don’t know why I’m doing this, and I don’t know what this function represents, so I might have to dig through a lot of code or find a lot of documentation to figure it out.

The fundamental problem here is that business rules and implementation logic are mixed together. What does that mean? Here, the green and pink diamond decisions are business rules, which are made to implement a function, and the product manager wants this rule combined with the other two. We use user.isgreenauth () and user.ispinkauth () to create a new rule, which is of course functionally fine. But the problem is that the rules and code here are fixed.

Let’s say that one day the product manager proposes a new demand, which requires not only green diamonds and pink diamonds, but also those who are older than 18 years old and have an annual income of more than 10W to enjoy this function. So the result is that we need in this is_satisfied function with many code, with the passage of time the function of the code will become more and more fat, and is likely to need to modify some of the judgment of the border, such as the age of 18 to 20 years old, such as 10 w to 30 w, etc., all of these are possible. When it comes time to make changes, you’ll find that because of the coupling and confusion of the code, the changes can be cumbersome.

To solve this problem, the introduction of a protocol is needed.

Meaning of the Statute

The meaning of the statute is to separate logic from rules, rules by rules, logic by logic.

Using the example above, for example, in a new requirement, the logic itself is very simple. That is, pink diamond + green diamond + age + income standard, this is the rule, and age and income standard is specific realization.

When we set the rules, we deconstruct the components, for example, the definition of income standard is annual income greater than 10W, for example, the definition of age standard is greater than 18 years old. We can make these components into separate modules, so that when we need to change the boundaries later, we only need to change them in the implementation, not in the rule part. Similarly, if we need to change the rules, we can avoid changes to the implementation, which is the point of the specification.

First, we need a framework to implement logical composition.

There are only three kinds of relationships between variables in logic: and or not. So the whole logic is pretty clear. Here we take an abstract approach, defining the interface first and then implementing it concretely. This is our specification of the condition, it has four interfaces, respectively is and or not the operation interface, and a is_SATISFIED judgment interface.

from abc import abstractmethod



class Specification:



    def and_specification(self, candidate):

        raise NotImplementedError()



    def or_specification(self, candidate):

        raise NotImplementedError()



    def not_specification(self, candidate):

        raise NotImplementedError()



@abstractmethod

    def is_satisfied(self, candidate):

        pass

Copy the code

Based on the Specification, we further implement and/or non-execution logic. The logic here is easy to understand without further explanation.

class AndSpecification(Specification):

    _one = Specification()

    _other = Specification()



    def __init__(self, one, other):

        self._one = one

        self._other = other



    def is_satisfied(self, candidate):

        return bool(self._one.is_satisfied(candidate) and self._other.is_satisfied(candidate))





class OrSpecification(Specification):

    _one = Specification()

    _other = Specification()



    def __init__(self, one, other):

        self._one = one

        self._other = other



    def is_satisfied(self, candidate):

        return bool(self._one.is_satisfied(candidate) or self._other.is_satisfied(candidate))





class NotSpecification(Specification):

    _wrapped = Specification()



    def __init__(self, wrapped):

        self._wrapped = wrapped



    def is_satisfied(self, candidate):

        return bool(not self._wrapped.is_satisfied(candidate))

    

    

The composition rule component is a logical combination of two specification conditions

class CompositeSpecification(Specification):

@abstractmethod

    def is_satisfied(self, candidate):

        pass



    def and_specification(self, candidate):

        return AndSpecification(self, candidate)



    def or_specification(self, candidate):

        return OrSpecification(self, candidate)



    def not_specification(self):

        return NotSpecification(self)

Copy the code

All of the above classes are for defining rules, and once we have them, we just need to populate them with specific business judgment logic. It’s like we split a complex business logic into a combination of sub-logic.

class User:

    def __init__(self, age=18, incoming=0, green_auth=False, pink_auth=False):

        self.age = age

        self.incoming = incoming

        self.green_auth = green_auth

        self.pink_auth = pink_auth





class UserSpecification(CompositeSpecification):

    def is_satisfied(self, candidate):

        return isinstance(candidate, User)



class GreenUserSpecification(CompositeSpecification):

    def is_satisfied(self, candidate):

        return getattr(candidate, 'green_auth'.False)

    

    

class PinkUserSpecification(CompositeSpecification):

    def is_satisfied(self, candidate):

        return getattr(candidate, 'pink_auth'.False)

    

    

class UserAgeSpecification(CompositeSpecification):

    def is_satisfied(self, candidate):

        return getattr(candidate, 'age'.0) > 18

    

    

class UserIncomingSpecification(CompositeSpecification):

    def is_satisfied(self, candidate):

        return getattr(candidate, 'incoming'.0) > 10

Copy the code

So we can separate out the logic and the rules, so that they don’t affect each other, and finally let’s look at an example of how it works.

ivan = User(green_auth=True)

lily = User(age=23, incoming=20, green_auth=True, pink_auth=True)



specification = UserSpecification().and_specification(PinkUserSpecification).and_specification(GreenUserSpecification).and_specification (UserAgeSpecification).and_specification(UserIncomingSpecification)





print(specification.is_satified(ivan))

print(specification.is_satified(lily))

Copy the code

The specification here is the specific rule proposed by the product manager. If we need to modify it in the future, we only need to modify its definition. If a specific piece of judgment logic needs to be changed, we find the corresponding code change so that the logic and other business code are not affected.

Daniel has said before, in a sense, the birth of design patterns, in fact, in response to product managers’ fickle needs and produced. I don’t know if you have such feelings after reading this example, at least I think it makes sense.

Well, that’s all for today’s article. I sincerely wish you all a fruitful day. If you still like today’s content, please join us in a three-way support.

Original link, ask a concern