Chain of Responsibility Pattern

The chain of responsibility refers to the behavioral design patterns.


Ганна Долбієва

The Jah-pictures film company shot a documentary about the Rastaman communists from Liberia called “The Red Dawn of Marley”. The film is very long (8 hours), interesting, but before being presented worldwide it turned out that in some countries moments and phrases from films may be considered heresy and do not give a rolling license. Producers of the film decide to cut the moments containing risky phrases from the film, manually and by computer. A double check is needed to ensure that representatives of the distributor are not simply shot in some countries, in the event of an error during manual inspection and installation.
Countries are divided into four groups – countries without censorship, with moderate, medium and very strict censorship. The decision is made to use neural networks to classify the level of heresy in the viewing fragment of the film. For the project, very expensive state-of-art neurons purchased with different levels of censorship detection are purchased, the developer’s task is to break the film into fragments and transfer them to chain of neural networks, from moderate to strict, until one of them detects heresy, then the fragment is sent to manual cut. It is impossible to make a walk through all the NNs, because too much computing power is spent on their work (we still have to pay for the electricity), it should stop on the first classify.
Naive pseudocode implementation:


import StateOfArtCensorshipHLNNClassifiers

protocol MovieCensorshipClassifier {
    func shouldBeCensored(movieChunk: MovieChunk) -> Bool
}

class CensorshipClassifier: MovieCensorshipClassifier {

    let hnnclassifier: StateOfArtCensorshipHLNNClassifier

    init(_ hnnclassifier: StateOfArtCensorshipHLNNClassifier) {
        self.hnnclassifier = hnnclassifier
    }
    
    func shouldBeCensored(_ movieChunk: MovieChunk) -> Bool {
        return hnnclassifier.shouldBeCensored(movieChunk)
    }
}

let lightCensorshipClassifier = CensorshipClassifier(StateOfArtCensorshipHLNNClassifier("light"))
let normalCensorshipClassifier = CensorshipClassifier(StateOfArtCensorshipHLNNClassifier("normal"))
let hardCensorshipClassifier = CensorshipClassifier(StateOfArtCensorshipHLNNClassifier("hard"))

let classifiers = [lightCensorshipClassifier, normalCensorshipClassifier, hardCensorshipClassifier]

let movie = Movie("Red Jah rising")
for chunk in movie.chunks {
    for classifier in classifiers {
        if classifier.shouldBeCensored(chunk) == true {
            print("Should censor movie chunk: \(chunk), reported by \(classifier)")
        }
   }
}

In general, the whole solution with an array of classifiers is not so bad, however! let’s imagine that we cannot create an array, we have the opportunity to create only one entity of the classifier, which already determines the type of censorship for a fragment of a film. Such restrictions are possible in the development of the library extending the functionality of the application (plugin).
We will use the decorator pattern – we will add the reference class to the next classifier in the classifier, we will stop the verification process at the first successful classification.
Thus, we implement the Chain of Responsibility pattern:


import StateOfArtCensorshipHLNNClassifiers

protocol MovieCensorshipClassifier {
    func shouldBeCensored(movieChunk: MovieChunk) -> Bool
}

class CensorshipClassifier: MovieCensorshipClassifier {

    let nextClassifier: CensorshipClassifier?
    let hnnclassifier: StateOfArtCensorshipHLNNClassifier

    init(_ hnnclassifier: StateOfArtCensorshipHLNNClassifier, nextClassifier: CensorshipClassifiers?) {
            self.nextClassifier = nextClassifier
            self.hnnclassifier = hnnclassifier
    }
    
    func shouldBeCensored(_ movieChunk: MovieChunk) -> Bool {
        let result = hnnclassifier.shouldBeCensored(movieChunk)
        
        print("Should censor movie chunk: \(movieChunk), reported by \(self)")
        
        if result == true {
                return true
        }
        else {
                return nextClassifier?.shouldBeCensored(movieChunk) ?? false
        }
    }
}

let censorshipClassifier = CensorshipClassifier(StateOfArtCensorshipHLNNClassifier("light"), nextClassifier: CensorshipClassifier(StateOfArtCensorshipHLNNClassifier("normal", nextClassifier: CensorshipClassifier(StateOfArtCensorshipHLNNClassifier("hard")))))

let movie = Movie("Red Jah rising")
for chunk in movie.chunks {
    censorshipClassifier.shouldBeCensored(chunk)
}

References

https://refactoring.guru/design-patterns/chain-of-responsibility

Source Code

https://gitlab.com/demensdeum/patterns/