Getting started with programming in Python design mode and getting started with python

Source: Internet
Author: User

Getting started with programming in Python design mode and getting started with python

Have you ever wondered what the design pattern is? This article shows why the design mode is so important. It uses several Python examples to demonstrate why the design mode is required and how to use it.
What is the design pattern?

The design patterns are summarized and optimized, and reusable solutions to some of the programming problems we often encounter. A design pattern does not act directly on our code as a class or a library. On the contrary, the design pattern is more advanced. It is a method template that must be implemented under specific circumstances. The design mode is not bound to a specific programming language. A good design model should be able to be implemented in most programming languages (if not all are done, it depends on the language features ). The most important thing is that the design model is also a double-edged sword. If the design model is used in an inappropriate situation, it will cause a disaster, which will lead to endless troubles. However, if the design pattern is used in the correct place at the right time, it will be your savior.

At first, you will think that the "pattern" is a wise action to solve a specific type of problem. That's right. It seems that many people work together to look at the problem from different perspectives and form the most common and flexible solution. You may have seen or solved these problems, but your solution may not be as complete as it is.

Although referred to as "design patterns", they are not closely related to the "design" field. The design pattern is different from the traditional analysis, design, and implementation. In fact, the design pattern is rooted in a complete concept in the program, therefore, it may appear in the analysis or higher-level design phase. It is interesting because the specific embodiment of the design pattern is the program code, therefore, it may make you think that it will not appear before the specific implementation phase (in fact, you did not realize that the specific design mode is being used before entering the specific implementation phase ).

You can understand the pattern through the basic concept of programming: add an abstraction layer. Abstract A thing is to isolate any specific details, so as to separate those unchanged core parts from other details. When you find that some parts of your program are often changed for some reason, and you do not want the modified parts to cause other changes, at this time, you need to think about the design methods that will not change. This will not only make the code more maintainable, but also make the code easier to understand, thus reducing development costs.

The difficulty in designing an elegant and easy-to-maintain program is to discover what I call "variable Vectors" (here, "vector" refers to the maximum gradient variation direction (maximum gradient), not a container class ). It means finding out the most important part of the change in the system, or in other words, finding out where the biggest cost of the system is. Once you find a variable vector, you can design your program around this focus.

The purpose of the design pattern is to separate the variable part of the code. If you look at this problem, you will immediately see multiple design patterns. For example, the Object-oriented inheritance (inheritance) can be seen as a design pattern (though implemented by the compiler ). It allows different behaviors (changed parts) through the same interface (unchanged parts ). A combination can also be considered as a design pattern because it allows changing the objects of the implementation class and their behavior dynamically or statically.

Another common design pattern example is the iterator. The iterator already exists with the use of the for loop since the beginning of Python, and is clearly a feature of Python. An iterator hides the specific implementation inside the container and provides a way to access each element in the container object in sequence. Therefore, you can use common code to perform corresponding operations on each element of a sequence without worrying about how the sequence is created. Therefore, your code can be effective for any object that can generate an iterator.

Three basic design patterns are listed here:

  1. Structured patterns are usually used to process the relationships between entities so that these entities can work together better.
  2. The creation mode provides the instantiation method and the corresponding object creation method for the appropriate condition.
  3. Behavior mode, used for communication between different entities, providing easier and more flexible communication methods for communication between entities.

Why should we use design patterns?

Theoretically, the design mode is a better solution to program problems. Countless programmers have encountered these problems and they use these solutions to solve them. So when you encounter the same problem, why do you have to think about creating a solution instead of using a ready-made one that proves to be effective?
Example

Assume that there is a task, and you need to find an effective method to merge two classes that do different things. In the existing system, these two classes are widely used in many different places, therefore, it is difficult to remove these two classes or modify the existing code. In addition, changing the existing code will lead to a lot of testing work, because in such a system that relies on a large number of different components, these modifications will always introduce some new errors. To avoid these troubles, you can implement a variant of Strategy Pattern and Adapter Pattern. These two modes can handle this problem well.

class StrategyAndAdapterExampleClass():   def __init__(self, context, class_one, class_two):    self.context = context    self.class_one = class_one    self.class_two = class_two   def operation1(self):    if self.context == "Context_For_Class_One":      self.class_one.operation1_in_class_one_context()    else:      self.class_two.operational_in_class_two_context()

It's easy, right? Now let's take a closer look at the policy model.
Rule Mode

Policy mode is a behavior-related design mode that allows you to determine the action of a program based on the specified context during running. You can encapsulate different algorithms in two classes and determine which policy to execute when running the program.

In the preceding example, the policy is determined based on the value of the context variable during instantiation. If the value of the given context variable is "class_one", class_one will be executed; otherwise, class_two will be executed.
Where can I use it?

Assume that you are writing a class to update or create a new user record and receive the same input parameters (such as name, address, and mobile phone number ), however, the corresponding update or creation method will be called according to different situations. Of course, you may use an if-else to determine how to handle this problem, but what if you need to use this class in different places? Then you have to constantly rewrite the if-else judgment. Why not simply solve this problem by specifying the context.
 

class User():  def create_or_update(self, name, address, mobile, userid=None):    if userid:      # it means the user doesn't exist yet, create a new record    else:      # it means the user already exists, just update based on the given userid

The conventional rule mode involves encapsulating algorithms into another class, but if so, that class is too wasteful. Remember not to stick to the template and grasp the flexibility of the core concepts. The most important thing is to solve the problem.

 
Adapter Mode

The adapter mode is a structural design mode that allows you to assign a new purpose to a class through different interfaces, so that systems using different call methods can use this class.

You can also change the input parameters received through the client class to adapt to the related functions of the adapter.
How to use it?

Another use of the adapter class is the wrapper, which allows you to wrap an action into a class and reuse the class in the appropriate circumstances. A typical example is that when you create a domain class for a table class cluster, You can encapsulate the same actions for different tables into an adapter class, instead of calling these different actions one by one. This not only enables you to reuse all the operations you want, but also does not need to rewrite the code when you use the same action in different places.

Two implementations are compared:
No adapter Solution

class User(object):  def create_or_update(self):    pass class Profile(object):  def create_or_update(self):    pass user = User()user.create_or_update() profile = Profile()profile.create_or_update()

If we need to do the same thing in different places or reuse this code in different projects, we need to repeat it.
Use a packaging Solution

Let's see how we do the opposite:
 

account_domain = Account()account_domain.NewAccount()

In this case, we use a packaging class to implement the account domain class:
 

class User(object):  def create_or_update(self):    pass class Profile(object):  def create_or_update(self):    pass class Account():  def new_account(self):    user = User()    user.create_or_update()     profile = Profile()    profile.create_or_update()

In this way, you can use the account domain when you need it. You can also package other classes under the domain class.
Factory Model

The factory model is a creation-type design model with its function as its name: This is a class that produces object instances like a factory.

The main purpose of this mode is to encapsulate object creation processes that may involve many classes into a separate method. Outputs the specified object instance through the given context.
When can I use it?

The best time to use the factory model is when you need to use multiple variants of a single object. For example, you have a button class, which has multiple variants, such as the example button, input box button, or flash button. You need to create different buttons in different scenarios. In this case, you can create different buttons in a factory.

Let's first create three classes:
 

class Button(object):  html = ""  def get_html(self):    return self.html class Image(Button):  html = "

Then create our factory class:
 

class ButtonFactory():  def create_button(self, typ):    targetclass = typ.capitalize()    return globals()[targetclass]()

: Globals () returns all global variables in a dictionary. Therefore, targetclass = typ. capitalize () will get the class name (Image, Input or Flash) through the passed typ string, while globals () [targetclass] will get the class through the class name (see the Meta class), while globals () [targetclass] () will create this class object.

We can use the factory class as follows:
 

button_obj = ButtonFactory()button = ['image', 'input', 'flash']for b in button:  print button_obj.create_button(b).get_html()

The output will be the HTML attribute of all button types. In this way, you can specify different types of buttons based on different situations, and it is easy to reuse them.
Decorator Mode

The decorator mode is a structural mode that allows us to add new or additional actions to an object at runtime, as appropriate.

The purpose is to apply Extended Function Methods to a specific object instance and generate the original object without a new method. It allows the combination of multiple decorators for one instance, so you will not see the instance bundled with a single ornament. This mode is an optional method for implementing subclass inheritance. Subclass Inheritance refers to integrating functions from the parent class. Unlike subclass inheritance, the corresponding behavior must be added during compilation. The modifier allows you to add new behaviors as needed during runtime.

Follow these steps to implement the decorator mode:

  1. Create a modifier class based on the original component class.
  2. Add the pointer field of a component class to the decorator class.
  3. Pass a component to the constructor of the decorator class to initialize the component class pointer.
  4. In the modifier class, point all component methods to the component class pointer, and,
  5. In the decorator class, rewrite each component method that needs to be modified.

Wikipedia (http://en.wikipedia.org/wiki/Decorator_pattern)
When can I use it?

The best time to use the decorator mode is when you have an entity that adds new actions as needed. Suppose you have an HTML link element, a Logout link, and you want to make minor changes to the specific behavior based on the current page. In this case, we can use the decorator mode.

First, build the decoration mode we need.

If you have logged on to the homepage, use the h2 tag to mark the Logout link.

If we have logged on to different pages, use the underline label to mark the link.

If you have logged on, use the bold link.

Once the decoration mode is set up, we can start work.

class HtmlLinks():  def set_html(self, html):    self.html = html   def get_html(self):    return self.html   def render(self):    print(self.html) class LogoutLink(HtmlLinks):  def __init__(self):    self.html = "<a href="logout.html"> Logout </a>" class LogoutLinkH2Decorator(HtmlLinks):  def __init__(self, logout_link):    self.logout_link = logout_link    self.set_html(" {0} ".format(self.logout_link.get_html()))   def call(self, name, args):    self.logout_link.name(args[0]) class LogoutLinkUnderlineDecorator(HtmlLinks):  def __init__(self, logout_link):    self.logout_link = logout_link    self.set_html(" {0} ".format(self.logout_link.get_html()))   def call(self, name, args):    self.logout_link.name(args[0]) class LogoutLinkStrongDecorator(HtmlLinks):  def __init__(self, logout_link):    self.logout_link = logout_link    self.set_html("<strong> {0} </strong>".format(self.logout_link.get_html()))   def call(self, name, args):    self.logout_link.name(args[0]) logout_link = LogoutLink()is_logged_in = 0in_home_page = 0 if is_logged_in:  logout_link = LogoutLinkStrongDecorator(logout_link)if in_home_page:  logout_link = LogoutLinkH2Decorator(logout_link)else:  logout_link = LogoutLinkUnderlineDecorator(logout_link) logout_link.render()

Singleton Mode

The Singleton mode is a design mode for creation. It ensures that only a single instance object exists for a class during runtime and provides a global access point to access this instance object.

This is because the globally unique access point "coordinates" access requests to other objects in the single instance, therefore, all the variables in the singleton will be the same.
When can I use it?

The Singleton mode may be the simplest design mode, which provides unique objects of a specific type. To achieve this goal, you must control the generation of objects outside the program. A convenient method is to use a single object of a private internal class as a singleton object.

class OnlyOne:  class __OnlyOne:    def __init__(self, arg):      self.val = arg    def __str__(self):      return repr(self) + self.val  instance = None  def __init__(self, arg):    if not OnlyOne.instance:      OnlyOne.instance = OnlyOne.__OnlyOne(arg)    else:      OnlyOne.instance.val = arg  def __getattr__(self, name):    return getattr(self.instance, name) x = OnlyOne('sausage')print(x)y = OnlyOne('eggs')print(y)z = OnlyOne('spam')print(z)print(x)print(y)print(`x`)print(`y`)print(`z`)output = '''<__main__.__OnlyOne instance at 0076B7AC>sausage<__main__.__OnlyOne instance at 0076B7AC>eggs<__main__.__OnlyOne instance at 0076B7AC>spam<__main__.__OnlyOne instance at 0076B7AC>spam<__main__.__OnlyOne instance at 0076B7AC>spam<__main__.OnlyOne instance at 0076C54C><__main__.OnlyOne instance at 0076DAAC><__main__.OnlyOne instance at 0076AA3C>'''

Because the built-in class is named with double underscores, it is private and cannot be accessed directly. The built-in class contains all the methods you want to put in the common class, and controls the creation through the constructor of the outer packaging class. When you create OnlyOne for the first time, an instance object is initialized, and the request for creating a new instance is ignored.

Use the _ getattr _ () method to direct all calls to the singleton instance. You can see from the output that although it seems that multiple objects (OnlyOne) have been created, the _ OnlyOne object has only one. Although there are multiple OnlyOne instances, they are all unique _ OnlyOne object proxies.

Note that the above method does not limit the creation of only one object, which is also a technology for creating a limited object pool. However, in that case, you may encounter problems with objects in the shared pool. If this is really a problem, you can solve this problem by designing the check-in and check-out mechanisms for shared objects.
Summary

In this article, I only list a few design patterns that I think are very important in programming. In addition, there are many design patterns that need to be learned. If you are interested in other design patterns, the design patterns section of Wikipedia can provide a lot of information. If it is not enough, you can take a look at the four-person book "design patterns: the basis for reusable object-oriented software". This book is a classic of design patterns.

Last thing: when using the design pattern, make sure that you are used to solve the correct problem. As I mentioned earlier, design patterns are a double-edged sword: improper use can lead to potential problems; if used properly, they will be indispensable.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.