Step by Step Haskell ii: Abstraction from imperative languages

This series is the summary and preparation of study notes after I learned “Learn You a Haskell For Great Good”.

The series is divided into five parts:

  • Let’s start with recursion
  • Abstraction from imperative languages
  • Haskell Preliminary: Syntax
  • Haskell advanced: Moniod, Applicative, Monad
  • Combat: Haskell and JSON

What is abstraction from mobile push and how

In this article we will cover a real development case. In the era of mobile Internet, iOS has APNs push technology to dominate the world, Android has GCM, but in China, almost all have been emasculated by domestic manufacturers. As a result, the domestic Android push services bloom, system manufacturers provided by Huawei, Xiaomi, third-party provided by aurora, Getui, etc. Today we will talk about how to access both aurora and Xiaomi’s push and see how to abstract it from the real business.

In the process of modeling, we can imagine that this is a good case of applying object-oriented thinking. First of all, push service needs to provide the following functions:

  • According to thepush_idSend push
  • According to theTag (tag, convenient group push method provided by third parties)Send push
  • According to thepush_idUpdate its tag
  • According to thepush_idQuerying an Owning Tag

So we can write a base class like this:

import abc

import requests


class AbstractPush(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def push_by_push_id(self, push_id_list):
        pass

    @abc.abstractmethod
    def push_by_tag(self, tag_list):
        pass

    @abc.abstractmethod
    def update_tag(self, push_id, add_tag_list, remove_tag_list):
        pass

    @abc.abstractmethod
    def query_tag(self, push_id):
        pass
Copy the code

All subclasses must implement these methods, for example we have aurora push:

# jpusn.py

from .base import AbstractPush


class JPush(AbstractPush):
    def push_by_push_id(self, push_id_list):
        pass

    def push_by_tag(self, tag_list):
        pass

    def update_tag(self, push_id, add_tag_list, remove_tag_list):
        pass

    def query_tag(self, push_id):
        pass
Copy the code

And Xiaomi push:

# mipusn.py

from .base import AbstractPush


class MiPush(AbstractPush):
    def push_by_push_id(self, push_id_list):
        pass

    def push_by_tag(self, tag_list):
        pass

    def update_tag(self, push_id, add_tag_list, remove_tag_list):
        pass

    def query_tag(self, push_id):
        pass
Copy the code

So the above code actually looks like this:

When we use it, we can instantiate different push objects and call the corresponding methods. For example, MiPush().push_by_push_id(“the_given_mi_push_id”).

This is classic object-oriented thinking.

What if we did the other way around? We know that all push implements the above method, but we don’t really need to know what push it is, just that it implements this method. It’s what we call the bridge pattern, and wikipedia explains it.

This leads to a relationship like this:

What kind of thinking is this based on? Let’s assume that each push is a black box, and each black box has four holes ABCD. Whichever black box drops something from the same numbered hole will always come out of another fixed hole. It’s like: A->C, B->C. This is the abstract of legend. We’re going to be using this capability a lot in Haskell.

In fact, we already use this capability in everyday programming. In Java, we call it an interface. Golang, too, has no explicit interface concept in Python, but with the example above we can create this abstraction. In C we often use function Pointers and structure Pointers to achieve this effect.

We use the above code described in Go as our summary.

type Push interface {
    push_by_push_id(push_id_list []string)
    push_by_tag(tag_list []string)
    update_tag(push_id string, add_tag_list []string, remove_tag_list []string)
    query_tag(push_id string)
}
Copy the code

Abstract is a powerful tool in software development, programming is actually a complex task broken down into countless small tasks, and then broken down the process. Abstraction, on the other hand, is the ability to find the common ground of countless small tasks and carve it out with one arrow.

This article is actually jiajunhuang.com/articles/20… A more detailed repetition of section 1, “Why Layering”, but abstraction is so important that it cannot be repeated a hundred times more.

conclusion

In this article, we saw how abstraction is done, and some small but big differences between abstraction and object-oriented processes, from a real production case. Next we’ll jump from the imperative language to the concrete syntax of Haskell to see if there are concepts of abstraction and interfaces in Haskell as well.