Design Patterns: Elements of Reusable Object-Oriented Software

Category: Computer Science
Author: Ralph Johnson, Erich Gamma, John Vlissides, Richard Helm
4.5
All Stack Overflow 198
This Year Reddit 49
This Month Reddit 3

About This Book

Capturing a wealth of experience about the design of object-oriented software, four top-notch designers present a catalog of simple and succinct solutions to commonly occurring design problems. Previously undocumented, these 23 patterns allow designers to create more flexible, elegant, and ultimately reusable designs without having to rediscover the design solutions themselves.

The authors begin by describing what patterns are and how they can help you design object-oriented software. They then go on to systematically name, explain, evaluate, and catalog recurring designs in object-oriented systems. With Design Patterns as your guide, you will learn how these important patterns fit into the software development process, and how you can leverage them to solve your own design problems most efficiently.

Each pattern describes the circumstances in which it is applicable, when it can be applied in view of other design constraints, and the consequences and trade-offs of using the pattern within a larger design. All patterns are compiled from real systems and are based on real-world examples. Each pattern also includes code that demonstrates how it may be implemented in object-oriented programming languages like C++ or Smalltalk.

Comments

by [deleted]   2019-08-24

If you want something challenging, dive into Design Patterns and see if you can recreate the examples in the book. I also recommend Code which covers the history of hardware and programming. It was the book that helped me understand how programming abstracts the physical components of the computer.

Reading is good, but you're already in school to study and learn stuff. I think your time would be much better spent on building apps / websites in your time off.

by insertAlias   2019-08-24

Personal opinion: for language-specific books, the hands-on ones are the only ones worth reading.

If you want "bedtime reading", I'd suggest books that are broader than learning a specific language. Books that discuss algorithms, or design patterns...stuff like that.

Speaking of design pattern books...https://www.amazon.com/dp/0201633612/ Not sure how much mileage you'll get out of that, but it's considered one of the best design patterns books that I've ever heard of.

by ttutisani   2019-08-24

My blog about software architecture: http://www.tutisani.com/software-architecture/ (may not be for very beginners but I hope that it's able to communicate important topics).

I'd also suggest reading the classic book about design patterns (a.k.a. Gang of Four): https://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612/ref=sr_1_3?crid=1XRJO0L09LHLY&keywords=design+patterns+elements+of+reusable+object+oriented+software&qid=1557502967&s=gateway&sprefix=design+patterns%2Caps%2C162&sr=8-3

There are several good thought leaders in this direction, specifically Martin Fowler (https://martinfowler.com/) and Eric Evans (he does not write much online, but his book is great - all about modeling properly): https://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215

​

I'm big on modeling, objects, etc. so reply back if any questions.

by sebscholl   2019-08-17
I'm ready this book right now, and it's great. https://www.amazon.com/Design-Patterns-Elements-Reusable-Obj...
by sid78669   2019-07-21

I would recommend reading Design Patterns: Elements of Reusable Object-Oriented Software. That book will give you the majority of design knowledge you would gain at this point in your career from college.

by UnityNorway   2019-07-21

I'm surprised Design Patterns: Elements of Reusable Object-Oriented Software isn't on the list. Old (1994), but gold.

by flares___   2019-07-21

Design Patterns (aka Gang of Four)

https://www.amazon.co.uk/Design-patterns-elements-reusable-object-oriented/dp/0201633612

by anonymous   2019-07-21

ShapeManager cannot create a shape if not knowing what this shape is (Square, Circle or something else). And it really doesn't know because you say the method createShare has no parameters. Either you misunderstood the question or the lecturer didn't explain it well. You should ask him/her for clarifications. If you look at the libraries of Java or any other OO language, I am pretty sure you won't find such scenario and implementation pattern as the one you gave in your example.


@croraf

You should find some other reading I think e.g. the classic book http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612. The main idea of a factory is that it returns something whose type the caller doesn't know, and doesn't care about. For example, if you have a method createSocket() in some SocketFactory, this method is usually defined to return an interface or an abstract class Socket. But actually it returns new SocketImpl1() and new SocketImpl2() which are concrete classes. What the factory returns may depend on many things - a system property, the underlying OS, anything you can think of. The main idea is that the factory centralizes the creation of Socket objects at one single place. This way, if you need to make a change, you can make it just in the factory. I think this book also has some decent Java counterparts too, you may look around. Other free good sources are referenced here.

Real world examples of Factory Method pattern

by anonymous   2019-07-21

Yes of course you can implement that
I'll draw a small architecture then ill explain it to u:

Architecture diagram

first of all , you can learn about Mappers here and TDGs here. A mapper has a method called cacheAll() which calls and delegate to TDG's method cacheAll() which in its turn has a mission to get all rows from a table from the db( the rows you want to cache in the cache object).

so basically first you have to create a listener implementing "ServletContextListener" which means its a listener for the whole servlet context, and inside its contextInitialized you have to call mp.fill(Mapper.cacheAll()), so it is sthg like ( this is general code, of course write it better and optimize it)

public class myServletContextListener implements ServletContextListener{

@Override
public void contextInitialized(ServletContextEvent sce) {
        mp.fill(Mapper.cacheAll());
 }

//
}

Don't forget to add your listener in web.xml:

<listener>
    <listener-class>myServletContextListener </listener-class>
</listener>

so what this will do , is on startup of the server, will cache all record into a hashmap mp in a cache object.

As for updating cache based on database change, you will have to use observer pattern.

UPDATE
I forgot to mention, about the cache object, i assume you want it accessible for all users or your app, so you should code it as a singleton (singleton pattern), code like that:

 public class cacheObject
{
    private static Map cMap;
    private static cacheObject cObject;
    private cacheObject()
    {
        cMap = Mapper.cacheAll();
    }
    public static synchronized cacheObject getInstance()
    {
        if (cObject == null){
            cObject = new cacheObject();
        }
        return cObject;
    }

}

Also if the data that you want to cache can be changed by users, so make it a Threadlocal singleton.

by anonymous   2019-07-21

Not necessarily video game related, but the best walk through I've seen for doing multi-platform software was in GOF (http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612). Read the case study on the windowing system.

by anonymous   2019-07-21

I would advise that you read the book 'Design Patterns' by Erich Gamma et al. (Amazon link: http://www.amazon.com/Design-Patterns-Object-Oriented-Addison-Wesley-Professional/dp/0201633612)

by rcavezza   2019-07-12
Refactoring by Martin Fowler is a great one https://www.amazon.com/Refactoring-Improving-Existing-Addiso...

Design Patterns is also very well known https://www.amazon.com/Design-Patterns-Elements-Reusable-Obj...

by CodeSheikh   2019-01-20
Nice list. Appreciate it. But I see there are a few amazing software books missing from the list such as:

- Clean Code (by "Uncle Bob")) [https://www.amazon.com/Clean-Code-Handbook-Software-Craftsma...]

- Design Patterns (by "Gang of 4") [https://www.amazon.com/Design-Patterns-Elements-Reusable-Obj...]

- Introduction to Algorithms (by "CLRS") [https://www.amazon.com/Introduction-Algorithms-3rd-MIT-Press...]

by anonymous   2019-01-13

I believe the famous recommendation of "favor composition over inheritance" was coined in the GoF Design Patterns book.

It says (p.20):

Favor object composition over class inheritance.

Ideally, you shouldn't have to create new components to achieve reuse. You should be able to get all the functionality you need just by assembling existing components through object composition. But this is rarely the case, because the set of available components is never quite rich enough in practice. Reuse by inheritance makes it easier to make new components that can be composed with old ones. Inheritance and object composition thus work together.

Nevertheless, our experience is that designers overuse inheritance as a reuse technique, and designs are often made more reusable (and simpler) by depending more on object composition. You'll see object composition applied again and again in the design patterns.

Notice that this statement refers to class inheritance, and must be distinguished from interface inheritance which is fine.

Dynamism

Both are ways to achieve reusability, but the advantage of composition over inheritance is dynamism. Since the composition can be changed dynamically at runtime this represents a great advantage, whereas inheritance is statically defined at compile time.

Encapsulation

Also, composition is based on using the public interfaces of the composed objects, therefore objects respect each other's public interfaces and therefore this fosters encapsulation. On the other hand, inheritance breaks encapsulation since child components typically consume a protected interface from the parent. It is a well known problem that changes in the parent class can break the child classes, the famous base class problem. Also in inheritance parent classes define the physical representation of subclasses, therefore child clases depend on parent classes to evolve.

Cohesion

Another advantage of composition is that it keeps classes focused on one task and this foster cohesion as well.

Liabilities

Evidently a problem with composition is that you will have more objects and fewer classes. That makes a little more difficult to visualize your design and how it achieves its goals. When debugging code it is harder to know what is going on unless you know what exact instance of a given composite is currently being used by an object. So composition makes designs a bit harder to understand in my opinion.

Since the advantages of composition are multiple that's why it is suggested to favor it over inheritance, but that does not mean inheritance is always bad. You can achieve a great deal when inheritance is properly used.

Interesting References

I would suggest a study of GoF Design Patterns to see good examples of both types of reusability, for instance a Strategy Pattern that uses composition vs a Template Method that uses inheritance.

Most of the patterns make a great use of interface inheritance and then object composition to achieve their goals and only a few use class inheritance as a reusability mechanism.

If you want to delve more the book Holub on Patterns, on chapter 2 has a section called Why extends is Evil that delve much more on the liabilities of class inheritance.

The book mentions three specific aspects

  • Losing Flexibility: The first problem is that explicit use of a concrete-class name locks you into a specific implementation, making down-the-line changes unnecessarily difficult.
  • Coupling: A more important problem with implementation inheritance is coupling, the undesirable reliance of one part of a program on another part. Global variables are the classic example of why strong coupling is bad. If you change the type of a global variable, for example, all the code that uses that variable—that is coupled to the variable—can be affected, so all this code must be examined, modified, and retested. Moreover, all the methods that use the variable are coupled to each other through the variable. That is, one method may incorrectly affect the behavior of another method simply by changing the variable’s value at an awkward time. This problem is particularly hideous in multithreaded programs.
  • Fragile-Base-Class Problem: In an implementation-inheritance system (one that uses extends), the derived classes are tightly coupled to the base classes, and this close connection is undesirable. Designers have applied the moniker “the fragile-base-class problem” to describe this behavior. Base classes are considered “fragile” because you can modify a base class in a seemingly safe way, but this new behavior, when inherited by the derived classes, may cause the derived classes to malfunction.
by anonymous   2019-01-13

Good opening slides for any education course in my opinion are:

  1. Why are we here? (Where has the need for this course been identified?)
  2. What do I expect to learn?
  3. Who should take this course? (What are the intended students, prerequisites, etc?)
  4. When can I apply what I’ve learned?
  5. Expectations of you (Participation, homework, tests, minimum classes to attend, etc)

For design patterns I could expect several visual tools or "job aids".

I would follow a structure similar to the Elements of Reusable Object-Oriented Software book:

  1. UML – Class Diagram Overview
  2. OOP – Abstraction, Encapsulation, Polymorphism, Inheritance
  3. Cohesion and Coupling
  4. What is a Design Pattern? – Pattern Name, The Problem, The Solution, The Consequences
  5. Why are Design Patterns so hard to learn?
  6. Why use Design Patterns?
  7. How to select a Design Pattern?
  8. How to use a Design Pattern?
  9. Cover various GoF design patterns with examples – Show examples of code before applying a design pattern, and how it looks after like Vince Huston does in his examples.
  10. Conclusion

As already mentioned, design patterns are really ideas, so when teaching you must convey the idea. If they understand the problem, solution and consequences of the design pattern, then they will be far better off than trying to force patterns into the code (and that will become a nightmare). Recognition of where and what patterns (if any) can be applied is the real goal. The Huston examples are really good for putting out an example of code to the class and seeing if they can identify a pattern to improve it. Hope this helps.

Head First Design Patterns is an excellent reference as well.

by anonymous   2019-01-13

I think the first thing that is needed here is a good / appropriate data structure to keep / manipulate the table data. That depends on specific requirements you can have, such as size of the table, performance requirements, etc.

Let's assume you will use some Matrix class which provides low-level operations over table (set cell value, add/remove row, transpose, etc).

This class will operate with basic data structures, for example, it may have get_row method which will return a list of numbers. Now we can, for example, get the summary of values in this list, but we can't just change some list item and have this change reflected in the parent Matrix (the row data is disconnected from the parent matrix structure).

Now we can build our structure upon this Matrix class, our two targets are:

1) make it more convenient for the user, some of the "conveniences" can be:

  • row, column and cell objects all connected to the parent Table object (if we modify the row item, it will be reflected in the parent table and other row / column / cell obejcts).
  • we can generate different views of the same data (such as pivot tables)
  • we can use special column/row addressing system (such as using 1, 2, 3, ... for rows and A, B, C, ... for columns)

2) hide the actual data structure we use to store the table data

  • this way we can work on Matrix implementation independently without breaking user code
  • we can even replace it with different structure (maybe we find something that is faster or something that takes less memory), or we can have different implementations for different situations (for example for desktop and mobile apps)

This is the approximate classes structure I would start with (python-like pseudo code):

class Matrix:
    """The base data structure, implementation detail."""

    get_cell(int x, int y):
        """Returns cell value by x/y column and row indexes."""

    set_cell(int x, int y, value):
        """Sets cell value by x/y column and row indexes."""

    get_row(int index) -> list:
        """Returns `list` of values in the `index` row."""

    get_column(int index) -> list;
     """Returns `list` of values in the `index` column."""

The Matrix class is a low level data structure and it should not be a part of a public interface.

The public interface is represented by Table class and other related classes below:

class Table:
    """The user-level interface to work with table data."""

    constructor():
        """Initializes Matrix object."""
        # The "_data" object is private, only to be used internally.
        self._data = Matrix()

    row(int number) -> Row:
        """Returns `Row` object by row number (1, 2, 3, ...)."""
        row = Row(self, number)
        self.attach(row)
        return row

    column(string name) -> Column:
        """Returns `Column` object by string name (A, B, C, ...)."""
        column = Column(self, name)
        self.attach(column)
        return column

    cell(int row_number, string col_name) -> Cell:
        """Returns `Cell` object by string name (A, B, C, ...)."""
        cell = Cell(self, row_number, col_name)
        self.attach(cell)
        return column

    attach(Observer observer):
        """Register an observer to be notified when Table state was changed."""
        self.observers.append(observer)

    _notify():
        """Notify all dependent objects about the state change."""
        for observer in self.observers:
            observer.update()

    ...

To keep Table and Row / Column / Cell objects in-sync we can use the Observer pattern.

Here the Table is a Subject and Row / Column / Cell are Observers. Once the state of the Table (and underlying data) is changed, we can update all dependent objects.

class Row(Observable):
    """Table row object."""

    constructor(Table parent, int index):
        self.parent = parent
        self.index = index
        self._data = None
        self.update()

    update()
        """Update row data.

        Fetches the `list` or row values from the `Matrix` object.
        """
        # Note: we have two choices here - the `Row`, `Column` and `Cell` objects
        # can either access `Table._data` property directly, or `Table` can provide
        # proxy methods to modify the data (like `_get_value(x, y)`); in both cases
        # there is a private interface to work with data used by `Table`, `Row`,
        # `Column` and `Cell` classes and the implementation depends on the language,
        # in C++ these classes can be friends, in python this can be just a documented
        # agreement on how these classes should work.
        # See also the comment in the `remove` method below.
        self._data = parent._data.get_row(index)

    sum():
        """Returns sum of row items."""
        sum = 0
        for value in self._data:
            sum += value
        return sum

    cell(string col_name):
        """Returns cell object."""
        return parent.cell(self.index, col_name)

    remove():
        """Removes current row."""
        # Here we access `parent._data` directly, so we also have to
        # call `parent._notify` here to update other objects.
        # An alternative would be a set of proxy methods in the `Table` class
        # which would modify the data and then call the `_notify` method, in such case 
        # we would have something like `self.parent._remove_row(self.index)` here.
        self.parent._data.remove_row(self.index)
        self.parent._notify()
        self.parent.detach(self)

The Column and Cell classes are similar, the Column will hold the column data and the Cell will wrap the cell value. The user-level usage can look like be this:

table = Table()
# Update table data
table.cell(1, "A").set(10)
table.cell(1, "B").set(20)
table.row(1).cell("C").set(30)
# Get row sum
sum = table.row(1).sum()

# Get the table row
row = table.row(1)
# The `remove` operation removes the row from the table and `detaches` it,
# so it will no longer observe the `table` changes.
row.remove()
# Now we have the detached row and we can put it into another table,
# so basically we cut-and-pasted the row from one table to another
another_table.add_row(row)

Using this approach you can quite easily implement such operations as copy, cut, paste. Also you can apply Command pattern here and extract these operations into small classes. This way it will also be quite easy to implement undo and redo.

The PivotTable table can also be a special kind of Observable. Depending on the requirements to the features for the pivot table, you may find Builder pattern useful to configure the pivot table. Something like this:

pivotBuilder = PivotBuilder(table)
# Group by column "A" and use `SumAggregator` to aggregate grouped values.
pivotBuilder.group_by_column("A", SumArggregator())  # or maybe pivotBuilder.groupBy(table.column("A"))
pivotTable := pivotBuilder.get_result()

The classes to export table to different formats probably don't have to be observable, so they'll just wrap the Table object and transform it to the appropriate format:

json_table = JsonTable(table)
data = json_table.export()

Of course, the above is just one of many possible implementation options, treat them as some ideas that can be useful (or not useful) depending on specific requirements you have.

You may find more ideas in the GoF patterns book.

by anonymous   2018-08-06

Decorator adds responsibilities for an object dynamically. Let's say we need to count the number of times an item is added to a Set (a kind of instrumentation detail). We have Set interface in java and we can implement a decorator to add the instrumentation behavior to an existing Set implementation like so.

public class InstrumentedSet<E> extends ForwardingSet<E> {
    private int addCount = 0;

    public InstrumentedSet(Set<E> s) {
        super(s);
    }

    @Override
    public boolean add(E e) {
        addCount++;
        return super.add(e);
    }

    @Override
    public boolean addAll(Collection<? extends E> c) {
        addCount += c.size();
        return super.addAll(c);
    }

    public int getAddCount() {
        return addCount;
    }

}

public class ForwardingSet<E> implements Set<E> {
    private final Set<E> s;

    public ForwardingSet(Set<E> s) {
        super();
        this.s = s;
    }

    @Override
    public int size() {
        return s.size();
    }

    @Override
    public boolean isEmpty() {
        return s.isEmpty();
    }

    @Override
    public boolean contains(Object o) {
        return s.contains(o);
    }

    @Override
    public Iterator<E> iterator() {
        return s.iterator();
    }

    @Override
    public Object[] toArray() {
        return s.toArray();
    }

    @Override
    public <T> T[] toArray(T[] a) {
        return s.toArray(a);
    }

    @Override
    public boolean add(E e) {
        return s.add(e);
    }

    @Override
    public boolean remove(Object o) {
        return s.remove(o);
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        return s.containsAll(c);
    }

    @Override
    public boolean addAll(Collection<? extends E> c) {
        return s.addAll(c);
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        return s.retainAll(c);
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        return s.removeAll(c);
    }

    @Override
    public void clear() {
        s.clear();
    }

}

There are lot more examples for Decorator pattern that you better take a look. For an instance, say you are developing Window based GUI application. You may need to add borders to the window, a scroll bar and so on. Some times you may need to add any combination of those. That is a good use of Decorator pattern as stated in the famous Design Patterns book [1] by Gamma. I would suggest you read this book [1] to find more about design patterns.

[1] https://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612

by xbrandnew99   2018-03-19

Design Patterns: Elements of Reusable Object-Oriented Software doesn't use JS for it's examples, but is highly regarded in learning design patterns.

Also, Mastering JavaScript Design Patterns is pretty good, and if I recall correctly, is modeled after the first book I mentioned. Heads up, there is a more up to date 2nd edition of this book available (linked version is 1st edition)

by rjcarr   2018-03-19

Not some book, but the book:

https://toptalkedbooks.com/amzn/0201633612

Again, not saying you need to read it cover-to-cover, but if you didn't even know it existed then that's likely a problem.

by BlueCoatEngineer   2018-03-19

kicks chair back to glance at shelf


Electronics:

The Art of Electronics, 3rd edition (Horwitz/Hill)

Learning the Art of Electronics (Hayes/Horowitz)

*Signal Integrity - Simplified (Bogatin)

Debugging - 9 Indispensible Rules... (Agans)

Software:

The C Programming Language (Kernighan / Ritchie)

The Practice of Programming (Kernighan / Pike)

Clean Code: A Handbook of Agile Software Craftmanship (Martin)

Design Patterns: Elements of Reusable Object-Oriented Software (Gamma, Helm, et al)

Computers:

*Computer Architecture, Fifth Edition: A Quantitative Approach (Hennessy / Patterson)


Note the repeated author names. :) Some of these might be a little beyond you since you're a freshman. I put a star in front of the ones that you might want to wait on until you've got more fundamentals built up. You don't have to wait for your school to teach them to you though.

A great way to jump-start your knowledge is to buy an Arduino experimentation kit (like Adafruit's ARDX) and learn how to use it. You'll get to play with where the code meets the hardware and you'll learn enough electronics knowledge to go all sorts of different directions.

Edit: almost forgot; teach yourself to draw like a mechanical engineer. There's likely an into to mechanical drawings course for the frosh Mechos, take it if you can. It comes up more often than you'd think and it'll help you learn to effectively communicate ideas visually.