This is the 11th day of my participation in the August More Text Challenge. For details, see:August is more challenging

The composite pattern is the last of the patterns detailed above in HeadFirst, and the preceding patterns are considered mature and frequently used patterns by the authors. So this is the last chapter of the detailed discussion of the model, which is also the longest, and I’m going to summarize and refine it. As the name suggests, composite patterns are used in combination with other patterns to solve a problem, but combining certain patterns does not make them composite. The composite pattern must be general enough to solve many problems. We all know that MVC is the application of composite patterns, so let’s look at how patterns are used together with the patterns used in MVC.

Model combined with

**** Remember the first mode, strategy mode begins with a duck, and the last mode ends with a duck. Let’s look at the duck example again to illustrate our composite pattern.

(1) First create a Quackable and then have some ducks implement the interface.

1 public interface Quackable 2 { 3 public void Quack(); 4} 5 5 public class RedheadDuck: Quackable 7 {8 public void Quack() 9 {10 console. WriteLine(" Quack "); 12 11}}Copy the code

(2) We wrote a class of red headed ducks, and then we added other kinds of ducks, such as rubber ducks.

1 public class RubberDuck: Quackable 2 {3 public void Quack() 4 {5 // 6 console. WriteLine(" creak "); 8 7}}Copy the code

(3) Test the example of writing, test the code

 

(4) When we have ducks, we may have a goose.

1 public class Goose 2 {3 public void Honk() {4 console. WriteLine(); 6 5}}Copy the code

(5) If we want to add the goose to the simulator, then we can use the adapter to adapt the goose to the duck for unified processing

1 public class GooseAdapter : Quackable 2 { 3 private Goose goose; 4 public GooseAdapter(Goose goose) { 5 this.goose = goose; 6 } 7 public void Quack() 8 { 9 goose.Honk(); 11 10}}Copy the code

(6) After we adapted the duck, we added the goose into the simulator

(7) If we want to know the number of quacks we need a decorator to give the duck some new behavior (the behavior of counting the quacks) by wrapping the duck into the decorator object. We don’t have to change the duck code.

1 public class QuackCounter : Quackable 2 { 3 Quackable duck; 4 private static int numberOfQuacks; 5 public QuackCounter(Quackable duck) 6 { 7 this.duck = duck; 8 } 9 10 public void Quack() 11 { 12 duck.Quack(); 13 numberOfQuacks++; 14 } 15 16 public static int GetQuacks() 17 { 18 return numberOfQuacks; 19}} 20Copy the code

(8) Package Quackable and count the number of calls.

(9) We want to manage the decorated and undecorated ducks separately, so that the created and decorated parts are wrapped up. We need to create a factory and a family of products for different types of ducks, so we use the abstract factory pattern.

1 /// <summary> 2 3 /// </summary> 4 public abstract class duckFactory 5 {6 public abstract Quackable CreateReadheadDuck(); 7 public abstract Quackable CreateRubberDuck(); 8} 9 10 11 /// <summary> 14 public class DuckFactory: AbstractDuckFactory 15 { 16 public override Quackable CreateReadheadDuck() 17 { 18 return new RedheadDuck(); 19 } 20 21 public override Quackable CreateRubberDuck() 22 { 23 return new RubberDuck(); </ /summary> 31 public class CountingDuckFactory: AbstractDuckFactory 32 { 33 public override Quackable CreateReadheadDuck() 34 { 35 return new QuackCounter(new RedheadDuck()); 36 } 37 38 public override Quackable CreateRubberDuck() 39 { 40 return new QuackCounter(new RubberDuck()); 41}} 42Copy the code

(10) Use factory mode

(11) With the factory pattern that creates ducks uniformly, we can also manage ducks uniformly, while the composite pattern allows us to treat collections of objects as if they were individual objects. The composition needs to implement the same interface as the leaf element, in this case the Quackable.

1 public class Flock : Quackable 2 { 3 private List<Quackable> quackables = new List<Quackable>(); 4 5 public void Add(Quackable quackable) { 6 quackables.Add(quackable); 7 } 8 public void Quack() 9 { 10 var enumerator= quackables.GetEnumerator(); 11 while (enumerator.MoveNext()) { 12 Quackable quackable = enumerator.Current; 13 quackable.Quack(); 14 15} 16} 17Copy the code

(12) In this combined pattern we use the essence of the foreach loop to iterate over the quack of the duck, which is actually another iterator pattern.

Then let’s modify the test simulator and see the output.

(13) Finally, we also integrate a requirement. When someone wants to observe the behavior of a duck, we can add an observer pattern to the duck.

An observer needs an Observable interface. An Observable is the object being observed. An Observable needs methods to register and notify observers.

1 public interface QuackObservable 2 { 3 public void RegisterObserver(Observer observer); 4 public void NotifyObservers(); 5}Copy the code

Duck implements QuackObservable. Since duck implements Quackable, we can make Quackable implement QuackObservable.

1 public interface Quackable:QuackObservable 2 { 3 public void Quack(); 4}Copy the code

(14) We need to implement registration and notification in each of duck’s classes, but here we can create a new Observable class that encapsulates the code for registration and notification, and then combine it with QuackObservable so that we only need a copy of the registration and notification code. All QuackObservable calls delegate to the Observable helper class.

1 public class Observable: QuackObservable 2 {3 // Observers 4 List<Observer> Observ = new List<Observer>(); 5 QuackObservable duck; 6 7 public Observable(QuackObservable duck) { 8 this.duck = duck; 9 } 10 11 public void RegisterObserver(Observer observer) 12 { 13 observers.Add(observer); 14 } 15 16 public void NotifyObservers() 17 { 18 foreach (var observer in observers) 19 { 20 observer.Update(duck); 21} 22} 23}Copy the code

(15) Then we take the redhead duck as an example to transform the observed, integrating the Quackable class and Observable.

1 public class RedheadDuck : Quackable 2 { 3 Observable observable; 4 public RedheadDuck() { 5 observable = new Observable(this); 6 } 7 public void RegisterObserver(Observer observer) 8 { 9 observable.RegisterObserver(observer); 10 } 11 12 public void NotifyObservers() 13 { 14 observable.NotifyObservers(); 15} 16 17 public void Quack() 18 {19 console. WriteLine(" Quack "); 20 NotifyObservers(); 22 21}}Copy the code

(16) If it’s a Flock of ducks, we modify the Flock class to register each leaf for observation when registered, and then when informed, each leaf calls NotifyObservers, and all Flock NotifyObservers don’t have to do anything.

 1     public class Flock : Quackable
 2     {
 3         private List<Quackable> quackables = new List<Quackable>();
 4 
 5         public void Add(Quackable quackable)
 6         {
 7             quackables.Add(quackable);
 8         }
 9 
10         public void Quack()
11         {
12             var enumerator = quackables.GetEnumerator();
13             while (enumerator.MoveNext())
14             {
15                 Quackable quackable = enumerator.Current;
16                 quackable.Quack();
17             }
18         }
19 
20         public void RegisterObserver(Observer observer)
21         {
22             foreach (var duck in quackables)
23             {
24                 duck.RegisterObserver(observer); 
25             }
26         }
27 
28         public void NotifyObservers(){}
29     }
Copy the code

(17) Now complete the Observer.

1 public interface Observer 2 { 3 void Update(QuackObservable duck); 4 } 5 6 public class QuackObserver : Observer 7 {8 public void Update(QuackObservable duck) 9 {10 console. WriteLine(" Observer: "+duck+" calling "); 12 11}}Copy the code

(18) Add observer test.

 

 

From this example we combine six design patterns, and you might ask is this a composite pattern? No, it’s just a bunch of models working together. A composite pattern is a group of patterns that are used together to solve a general problem. This example is just to show how patterns can be combined, but it is not intended to solve a general problem.

Using the above code, let’s draw a class diagram to help you understand how the patterns in the example work together.

 

 

Composite patterns: The combination of two or more patterns to form a solution to a general problem that is recurring.

MVC Composite Pattern

M: Model. The model holds all data, state, and program logic. V: Visual view, used to present state and data, is the interface with the user interaction. C: control, which takes input from the user and tells the model how to act accordingly. The view is an object that can be adjusted to use different controllers (different policies). Composite mode: Each display component in the interface is either a composite node or a leaf node. When the controller wants to make some kind of update, it just tells the topmost component of the view that the composite pattern handles the update of the composite node or leaf node. Observation mode: When the model changes, it needs to be fed back to the view immediately. In this case, the controller or view can act as an observer to observe the dynamic changes of the model. This model is completely independent of the view and controller and is a loosely coupled implementation. Although the design pattern in MVC may no longer try to model in the classical sense, but in reality, the design pattern does not necessarily copy the classic design, there will be optimization or modification, so it does not affect the use of design pattern.

So these are the concepts and examples of composite patterns, and all the detailed patterns in HeadFirst are over, so next time I’ll list other design pattern concepts that I haven’t covered in detail, and maybe used elsewhere and I’ll come back and complete the examples and code.