DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Authorization Using Reverse Proxy Design Pattern in Cloud Environment
  • Designing for Sustainability: The Rise of Green Software
  • Avoiding If-Else: Advanced Approaches and Alternatives
  • Comprehensive Proxy Server Guide: Types, Applications, and Developer Examples

Trending

  • Feature Flag Debt: Performance Impact in Enterprise Applications
  • RAG Is Not Enough: Advanced Retrieval Architectures Using Vertex AI Search on GCP
  • Pragmatica Aether: Let Java Be Java
  • Detecting Bugs and Vulnerabilities in Java With SonarQube
  1. DZone
  2. Software Design and Architecture
  3. Integration
  4. Software Design Patterns and Principles

Software Design Patterns and Principles

An introduction to good object-oriented principles and design patterns every software programmer should be using on a daily basis.

By 
Shobhit Kukreti user avatar
Shobhit Kukreti
·
Tanvi Hungund user avatar
Tanvi Hungund
·
Priyank Singh user avatar
Priyank Singh
·
Karthik Kamarapu user avatar
Karthik Kamarapu
·
Dhanveer Nambiar user avatar
Dhanveer Nambiar
·
Jun. 05, 24 · Tutorial
Likes (2)
Comment
Save
Tweet
Share
3.4K Views

Join the DZone community and get the full member experience.

Join For Free

Design patterns are a set of templates formulated over a period of time by software architects. They are best practices that software programmers can apply to their own software/application development. They provide incredible advantages by saving time and effort by reusing pre-existing solutions while improving the quality and consistency of the code. It can also help enhance communication and collaboration with other developers, facilitate the adaptation and evolution of your code, and prevent common pitfalls and errors. All in all, design patterns are a great way to streamline your programming process. 

Broadly speaking there are three kinds of patterns: structural, creational, and behavioral.

  • Creational Patterns are concerned with the creation of an object and separating the object creation from the client that will use the object. Examples include Singleton, Factory, and Factory Method. 
  • Behavioral Patterns define how multiple objects interact with each other. Command Patterns, Iterator Patterns, and Observer Patterns are some of the common behavioral patterns. The patterns show how different components of the system behave and respond to each other. It can improve the code by enhancing flexibility, modularity, and reusability.
  • Structural patterns, on the other hand, deal with the composition and organization of classes and objects. It can hide the complexity of the system by composing classes and objects into larger structures. Examples include Adapter, Composite, Decorator, Facade, and Proxy.

While design patterns are a tried and tested solution, they are formed on the backs of good object-oriented programming principles. Some of the key principles are listed below:

  • Program to an interface: Keeps the design flexible.
  • Identify the sections of your software that can vary and separate them from the sections that vary: Keep the design modular
  • Favor composition over inheritance: Compose the large structure with individual objects.
  • Loose coupling: Minimize interdependency on objects.
  • The open/closed principle: Class software once code is completed, tested, and validated should be closed for modification but the class is open to extension by means of inheritance.
  • Dependency inversion: Depend on abstract or interfaces rather than concrete instantiation of classes.
  • Single responsibility principle: A class is responsible for only one requirement.

Example: Proxy Pattern

We chose the Structural Proxy Pattern for our discussion. It is a popular pattern especially used in distributed systems as a Remote Proxy. Proxy Pattern, as the name suggests, is a proxy for someone else. A proxy-designed class provides public-facing APIs that clients use to send requests. The proxy class has the means to access the real object service and can serve the request to it after say authentication of the request from the client. Furthermore, a proxy pattern can allow for lazy initialization. If the real object creation is deemed expensive, we can delay its instantiation only when it is needed by a client.  It also allows for logging and caching which can be implemented in the proxy class methods.  In the case of distributed systems where the client and the proxy object are on one node and the service real object which services the request is on another node, the proxy pattern allows for a uniform view and the client is unaware of which node is servicing the object. 

Fig. 1: Proxy Pattern

Fig. 1: Proxy Pattern

Figure 1 shows an architecture diagram of the proxy pattern. It has a client class that contains a handle to the ProxyObject. The ProxyClass and RealClass both derive from the iProxy interface class and implement the APIs. To be able to communicate between the two nodes, both additionally have a CommObject which is responsible for the serialization and de-serialization of commands and data when shared over the network. The code snippet provides a minimal set of class and method declarations to visualize how the distributed system would operate together.

C++
 


// CommClass provides serialization/deserialization to
// to share data and command in a distributed system
class CommClass {

  // RealClass registers a callback with the CommClass to receive command 
  // and data from the proxy
  typedef std::function<void(unsigned, vector<unsigned>)> fCallBack;
  
  public:
  	CommClass() {}
	~CommClass() {}

  	// Proxy Class Uses the CommClass Object to send command and data to the remote service
  	void sendToRemoteService(unsigned cmd, std::vector<unsigned> data);

	// Remote Service Class is notified via event. It uses the registered callback
  	// to call into the remote service RealClass
  	void receiveFromProxy(unsigned cmd, std::vector<unsigned> data)
    {
    	_cb(cmd, data);
    }
  
  	void registerCallBack(fCallBack cb) { _cb = cb; }
  
  private:
  	fCallBack _cb;

  
};


// Proxy Interface Class declares the public facing methods
class iProxy {

  public:
  	iProxy() {}
  	virtual ~iProxy() {}
  
  	virtual void methodOne() = 0;
  	virtual void methodTwo() = 0;

};

// Concrete class which implements the interface class methods and
// lives on the same node as the client
class ProxyClass : public iProxy {

  public:
  	ProxyClass() {};
  	~ProxyClass() {};
  
  	// Implement Interfaces
  	void methodOne() {};
  	void methodTwo() {};
  
  private:
  	CommClass CommObject;
  
};

// Real Class which implements the Proxy Interface methods and is the service provider
class RealClass : public iProxy {

  public:
    RealClass() {};
    ~RealClass() {};
  
  // implement the interfaces
    void methodOne() {};
    void methodTwo() {};

  private:
  	CommClass CommObject;
  
};


Conclusion

The example Proxy Pattern is an important arrow in any software engineer's quiver. By using the principle of composition, we can control access to internal objects, add additional logic such as caching and logging around APIs as well add security. It allows for lazy initialization which is useful in a resource-constrained environment. Certain disadvantages such as added overhead and complexity do exist and therefore, this is not a one-size-fits-all solution.  

While Proxy Pattern offers a robust solution to many common design challenges, any design pattern should be used with caution to not overcomplicate your design. Always start with the simpler object-oriented principles and then switch to a design pattern when your architecture starts resembling a specific pattern.

Loose coupling Proxy pattern Software design pattern

Opinions expressed by DZone contributors are their own.

Related

  • Authorization Using Reverse Proxy Design Pattern in Cloud Environment
  • Designing for Sustainability: The Rise of Green Software
  • Avoiding If-Else: Advanced Approaches and Alternatives
  • Comprehensive Proxy Server Guide: Types, Applications, and Developer Examples

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook