avatarEsteban Thilliez

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

3507

Abstract

.download_file(file)

user = User(<span class="hljs-string">'admin'</span>)
user.download_file(file)</pre></div><p id="e48d">In this example, the <code>User</code> class is responsible for checking if the user is authorized to download a file, and the <code>File</code> class is responsible for downloading the file. This design violates the Single Responsibility Principle because the <code>File</code> class is responsible for both representing a file and providing the functionality to download the file. The <code>User</code> class is also responsible for checking the authorization of the user, which could be a more complex process.</p><p id="653a">Also, if there are any other security or access control checks that needs to be done before downloading the file, it would need to be implemented in the <code>User</code> class, making it more complex and harder to maintain.</p><h2 id="89b9">Solution</h2><p id="bd31">This problem can be solved by introducing a <code>FileProxy</code> class that acts as a proxy for the <code>File</code> class and controls access to the underlying file. This way we can separate the responsibilities of checking the authorization, and the download process.</p><div id="1eee"><pre><span class="hljs-keyword">class</span> <span class="hljs-title class_">File</span>:
<span class="hljs-keyword">def</span> <span class="hljs-title function_">__init__</span>(<span class="hljs-params">self, file_path</span>):
    self.file_path = file_path

<span class="hljs-keyword">def</span> <span class="hljs-title function_">download</span>(<span class="hljs-params">self</span>):
    <span class="hljs-built_in">print</span>(<span class="hljs-string">f'Downloading <span class="hljs-subst">{self.file_path}</span>'</span>)

<span class="hljs-keyword">class</span> <span class="hljs-title class_">FileProxy</span>: <span class="hljs-keyword">def</span> <span class="hljs-title function_">init</span>(<span class="hljs-params">self, file_path, user</span>): self.file = File(file_path) self.user = user

<span class="hljs-keyword">def</span> <span class="hljs-title function_">download</span>(<span class="hljs-params">self</span>):
    <span class="hljs-keyword">if</span> self.user != <span class="hljs-string">'admin'</span>:
        <span class="hljs-built_in">print</span>(<span class="hljs-string">'You are not authorized to download this file'</span>)
    <span class="hljs-keyword">else</span>:
        self.file.download()

<span class="hljs-keyword">class</span> <span class="hljs-title class_">User</span>: <span class="hljs-keyword">def</span> <span class="hljs-title function_">init</span>(<span class="hljs-params">self, name</span>): self.name = name

<span class="hljs-keyword">def</span> <span class="hljs-title function_">download_file</span>(<span class="hljs-params">self, file</span>):
    file.download()

<span class="hljs-keyword">if</span> name == <span class="hljs-string">"main"</span>: user = User(<span class="hljs-string">'guest'</span>) file = FileProxy(<span class="hljs-string">'important_file.txt'</span>, user.name) user.download_file(file)

user = User(<span class="hljs-string">'admin'</span>)
file = FileProxy(<span class="hljs-string">'important_file.txt'</span>, user.name)
user.download_file(file)</pre></div><p id="f751">This design separates the responsibilities of checking the authorization and the download proc

Options

ess, making the code more maintainable and extensible. The <code>File</code> class only needs to be concerned with providing the functionality to download the file and the <code>FileProxy</code> class is responsible for controlling access to the file.</p><p id="26c2">Also, the <code>FileProxy</code> class can be easily extended to add other security checks.</p><h2 id="3988">Applications</h2><ul><li>Controlling access to an object or a resource</li><li>Adding functionality to an object without modifying the object itself</li><li>Creating a more lightweight version of an object</li><li>Creating a virtual representation of an object</li></ul><h2 id="f2e1">Advantages</h2><ul><li>Separates the responsibilities of controlling access to an object and providing the functionality of the object</li><li>Makes code more maintainable and extensible by reducing the complexity of the objects being used</li><li>Allows for the addition of functionality to an object without modifying the object itself</li></ul><h2 id="e459">Disadvantages</h2><p id="c3c2">I don’t really see disadvantages to using the Proxy pattern, except the fact that it can increase the complexity by adding an abstraction layer, and by adding more classes and interfaces.</p><h2 id="569b">Final Note</h2><p id="028d">The Proxy pattern is a bit hard to understand at first, but it can be useful in various situations, especially when you want to separate the responsibilities of controlling access to an object and providing the functionality of the object, making the code more maintainable and extensible.</p><p id="545b"><i>To explore the other stories of this story, click below!</i></p><div id="ad69" class="link-block"> <a href="https://readmedium.com/improve-your-python-coding-with-design-patterns-4430a5de82b5"> <div> <div> <h2>Improve your Python Coding with Design Patterns</h2> <div><h3>Common Design Solutions to Solve Common Design Problems</h3></div> <div><p>medium.com</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*OHUcHuz31VW1jXvW)"></div> </div> </div> </a> </div><p id="dc9e"><i>To explore more of my Python stories, click <a href="https://readmedium.com/tech-aa824bad0d67">here</a>! You can also access all my content by checking <a href="https://readmedium.com/about-me-d63607c8c341">this page</a>.</i></p><p id="8692"><i>If you want to be notified every time I publish a new story, subscribe to me via email by clicking <a href="https://medium.com/subscribe/@estebanthi">here</a>!</i></p><p id="7770"><i>If you’re not subscribed to medium yet and wish to support me or get access to all my stories, you can use my link:</i></p><div id="a2d6" class="link-block"> <a href="https://medium.com/@estebanthi/membership"> <div> <div> <h2>Join Medium with my referral link — Esteban Thilliez</h2> <div><h3>Read every story from Esteban Thilliez (and thousands of other writers on Medium). Your membership fee directly…</h3></div> <div><p>medium.com</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*IoN4BofrwCNWA_bS)"></div> </div> </div> </a> </div></article></body>

The Proxy Pattern in Python

Control access to objects while adding functionality or making them virtual

Photo by Brett Jordan on Unsplash

This story is part of the “Design Patterns” series. You can find the other stories of this series here:

You can also find all the code used through this series on GitHub.

The Proxy pattern is a design pattern used to provide a surrogate or placeholder object which references an underlying object. The proxy controls access to the underlying object and can add additional functionality or behavior.

Problems the Proxy Pattern can Solve

Imagine that we’re building a system that allows users to upload and download files. The system has a File class that represents a file on the server, and a User class that represents a user of the system.

class File:
    def __init__(self, file_path):
        self.file_path = file_path

    def download(self):
        # Code to download the file
        print(f'Downloading {self.file_path}')

class User:
    def __init__(self, name):
        self.name = name

    def download_file(self, file):
        if self.name != 'admin':
            print('You are not authorized to download this file')
        else:
            file.download()


if __name__ == "__main__":
    file = File('important_file.txt')
    user = User('guest')
    user.download_file(file)

    user = User('admin')
    user.download_file(file)

In this example, the User class is responsible for checking if the user is authorized to download a file, and the File class is responsible for downloading the file. This design violates the Single Responsibility Principle because the File class is responsible for both representing a file and providing the functionality to download the file. The User class is also responsible for checking the authorization of the user, which could be a more complex process.

Also, if there are any other security or access control checks that needs to be done before downloading the file, it would need to be implemented in the User class, making it more complex and harder to maintain.

Solution

This problem can be solved by introducing a FileProxy class that acts as a proxy for the File class and controls access to the underlying file. This way we can separate the responsibilities of checking the authorization, and the download process.

class File:
    def __init__(self, file_path):
        self.file_path = file_path

    def download(self):
        print(f'Downloading {self.file_path}')


class FileProxy:
    def __init__(self, file_path, user):
        self.file = File(file_path)
        self.user = user

    def download(self):
        if self.user != 'admin':
            print('You are not authorized to download this file')
        else:
            self.file.download()


class User:
    def __init__(self, name):
        self.name = name

    def download_file(self, file):
        file.download()


if __name__ == "__main__":
    user = User('guest')
    file = FileProxy('important_file.txt', user.name)
    user.download_file(file)

    user = User('admin')
    file = FileProxy('important_file.txt', user.name)
    user.download_file(file)

This design separates the responsibilities of checking the authorization and the download process, making the code more maintainable and extensible. The File class only needs to be concerned with providing the functionality to download the file and the FileProxy class is responsible for controlling access to the file.

Also, the FileProxy class can be easily extended to add other security checks.

Applications

  • Controlling access to an object or a resource
  • Adding functionality to an object without modifying the object itself
  • Creating a more lightweight version of an object
  • Creating a virtual representation of an object

Advantages

  • Separates the responsibilities of controlling access to an object and providing the functionality of the object
  • Makes code more maintainable and extensible by reducing the complexity of the objects being used
  • Allows for the addition of functionality to an object without modifying the object itself

Disadvantages

I don’t really see disadvantages to using the Proxy pattern, except the fact that it can increase the complexity by adding an abstraction layer, and by adding more classes and interfaces.

Final Note

The Proxy pattern is a bit hard to understand at first, but it can be useful in various situations, especially when you want to separate the responsibilities of controlling access to an object and providing the functionality of the object, making the code more maintainable and extensible.

To explore the other stories of this story, click below!

To explore more of my Python stories, click here! You can also access all my content by checking this page.

If you want to be notified every time I publish a new story, subscribe to me via email by clicking here!

If you’re not subscribed to medium yet and wish to support me or get access to all my stories, you can use my link:

Design Patterns
Software Development
Programming
Python
Coding
Recommended from ReadMedium