C# Patterns and Anti-Patterns

Content

  • C# Design Pattern
  • Design Patterns used in .Net framework
  • C# worst Anti-Patterns

Creational Patterns

Abstract Factory?

Lets you produce families of related objects without specifying their concrete classes.


Builder?

Lets you construct complex objects step by step. The pattern allows you to produce different types and representations of an object using the same construction code.


Factory Method?

Provides an interface for creating objects in a superclass, but allows subclasses to alter the type of objects that will be created.


Prototype?

Lets you copy existing objects without making your code dependent on their classes.


Singleton?

Lets you ensure that a class has only one instance, while providing a global access point to this instance.

Structural Patterns

Adapter?

Allows objects with incompatible interfaces to collaborate.

Bridge?

Lets you split a large class or a set of closely related classes into two separate hierarchies—abstraction and implementation—which can be developed independently of each other.

Composite?

Lets you compose objects into tree structures and then work with these structures as if they were individual objects.

Decorator?

Lets you attach new behaviors to objects by placing these objects inside special wrapper objects that contain the behaviors.

Facade?

Provides a simplified interface to a library, a framework, or any other complex set of classes.

Flyweight?

Lets you fit more objects into the available amount of RAM by sharing common parts of state between multiple objects instead of keeping all of the data in each object.

Proxy?

Lets you provide a substitute or placeholder for another object. A proxy controls access to the original object, allowing you to perform something either before or after the request gets through to the original object.

Behavioral Pattern

Chain of Responsibility?

Lets you pass requests along a chain of handlers. Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain.

Command?

Turns a request into a stand-alone object that contains all information about the request. This transformation lets you pass requests as a method arguments, delay or queue a request's execution, and support undoable operations.

Iterator?

Lets you traverse elements of a collection without exposing its underlying representation (list, stack, tree, etc.).

Mediator?

Lets you reduce chaotic dependencies between objects. The pattern restricts direct communications between the objects and forces them to collaborate only via a mediator object.

Memento?

Lets you save and restore the previous state of an object without revealing the details of its implementation.

Observer?

Lets you define a subscription mechanism to notify multiple objects about any events that happen to the object they're observing.

State?

Lets an object alter its behavior when its internal state changes. It appears as if the object changed its class.

Strategy?

Lets you define a family of algorithms, put each of them into a separate class, and make their objects interchangeable.

Template Method?

Defines the skeleton of an algorithm in the superclass but lets subclasses override specific steps of the algorithm without changing its structure.

Visitor?

Lets you separate algorithms from the objects on which they operate.

Design patterns used in .Net framework

Abstract Factory pattern is used in the ADO.NET 2.0 infrastructure (DbProviderFactory class)

Template Method pattern is used in many parts of the framework (WinForms, WPF...)

Builder pattern is also used quite often (DbConnectionStringBuilder, UriBuilder...)

Prototype - Specify the kind of objects to create using a prototypical instance, and create new objects by copying this prototype.

ICloneable interface with method Clone() is classic example of prototype.

Predefined instances (static properties) of StringComparer, Encoding, Color, etc are a variant of the Prototype pattern

Proxy pattern is everywhere when you use .NET remoting

Events are a variant of the Observer pattern

The Iterator pattern is used in collections

Iterator pattern - all implementations of IEnumerable.

The Strategy pattern is used, for instance, in cryptography classes

Visitor Pattern in ExpressionVisitor class (Syste.Linq.Expression namespace).

Adapter Pattern in System.Web.Abstractions - wrap up various Web classes (HttpRequest, HttpResponse) in a more unit testable way - i.e. HttpResponseBase.

Factory Method - Activator.CreateInstance - creates an instance of specified object.

Fa?ade - Higher level interface to a set of interfaces in a subsystem

MessageBox (System.Windows.Forms) - provides a reusable high level interface to some of the Windows Forms interfaces,?instead of writing a whole lot of code to present a dialog you can just call MessageBox.Show("Hello world");.

Flyweight - Use sharing to support large numbers of fine-grained objects efficiently. The .Net framework uses String Interning to save memory on identical strings, this is an implementation of the Flyweight pattern.?

Provider pattern - used in MembershipProvider, RoleProvider, ProfileProvider.

Anti-Pattern

God Class

This type of class might have many responsibilities, and the class itself usually serves as a direct parent for other, more specialized classes. As the name implies, when such classes exist in a system, they are considered gods because they often hold many responsibilities and powers they delegate to their children. While this approach might look useful, this can lead to an explosion of complex and difficult code.

Spaghetti code

The term “spaghetti code” is used to describe a large tangled mess of code due to its complexity or lack of structure. It consists mainly of many classes and methods with many inter-dependences between them. This design smell can also happen if you don’t use proper design patterns to separate business logic from the UI code.

Magic numbers and strings

When you use strings in your code, you need to define them as constants or variables throughout the different methods of your framework. This will help other programmers reading your code to understand its purpose, as well as other questions related to that particular section.

Yoda conditions

Yoda conditions occur when you reverse the usual order of parameters in the if condition. I have seen programmers who do this to make their code more concise.

if (5 == numberOfOrders) { //do something }

As the name implies, these “Yoda conditions” make your code look like it has been written by Yoda, the Jedi Master from Star Wars. It makes your code harder to read and understand.

Interface bloat (fat interface)

Interface bloat is a design anti-pattern that leads to an interface that is unnecessarily cluttered, confusing, and hard to use.

The root cause behind interface bloat is a lack of prioritization. The designers behind the interface didn’t decide which features were important and which ones weren’t, so they added every feature and then some. When you combine lots of features with a lack of clarity, you end up with the opposite of an intuitive interface.


Primitive Obsession

A primitive obsession anti-pattern occurs when developers create classes containing only primitive data types such as integers or strings. Instead of using primitive data types, developers should use object-oriented classes to group the primitive properties. This is because they provide a greater degree of flexibility.


Poltergeist

The Poltergeist anti-pattern occurs you have a class in your application that delegates the whole work to other classes.

I occasionally see this type of class during a code review. It’s usually because the code has multiple layers. But in this case, one layer doesn’t do anything else than delegating work to another layer. This can quickly become a recurring problem, but it’s important to identify it as soon as possible.


Premature generalization

Premature generalization is an anti-pattern in software development where you create classes that are overly generic and too flexible. You make these classes generic to reduce code duplication, but this often makes your code hard to understand and maintain.

To avoid this, don’t make your classes generic too early. Make them generic only when you notice that the logic for manipulating types is repeating itself. This will make your code easier to maintain, understand and extend..


Shotgun Surgery

Shotgun surgery is a term in software engineering that means making changes in lots of places at once to implement a feature. The changes themselves might seem minor, but they must be applied in multiple places in the code.

It is called shotgun surgery because making so many changes at once is a lot like the quick-and-dirty approach to solving a medical problem with a shotgun, such as when a doctor does not have time to diagnose the issue fully and performs several diagnostic tests all at once.


Golden Hammer

Golden hammer is a term used in object-oriented programming to describe a popular tool that is overused to the point of becoming ineffective. In short, a golden hammer is a tool that is used repeatedly for tasks for which it is not well suited.

For example, if you are a programmer and always try to use the same technology to address different problems, you may be using a golden hammer.

Cargo Cult Programming

Cargo Cult Programming is an anti-pattern in which programmers use solutions they don’t really understand.

Programmers following this antipattern will often use a design pattern in places where that pattern shouldn’t be used. One example of this antipattern would be to use 2-3 design patterns to write a simple Hello World application.

Error Hiding

Error Hiding is a programming anti-pattern in which you don’t provide enough information to the client, so they know how to use your system successfully.

This happens when you catch an exception within the system, but you don’t provide enough information to the user. Catching an exception but not doing anything with it is an antipattern.


Conclusion

It is important to understand and master design patterns, but we also need to learn anti-patterns.

They are not in any way opposites; they are different ways to achieve the same goal, so we need to know and understand them both in order to be the best developer possible.

This is one of the most important things to remember when learning about SOLID principles and design patterns: don’t get hung up on them as inspiration. These can be used as a guide if you’re stuck or struggling with a problem—but they may not apply perfectly to our situation or may not be necessary at all.

要查看或添加评论,请登录

Kashyap Narayanan的更多文章

社区洞察

其他会员也浏览了