1. The opening

1. What are design patterns?

In our actual development, we often encounter some specific problems, and these problems may be repeated, the emergence of a design pattern is for a specific problem, put forward a solution. Because design patterns do not provide a concrete code implementation, they are universal across languages. For example, the object-oriented design pattern expresses relationships and interactions through classes and objects.

Design patterns can be divided into three broad categories:

  1. Structural Design Pattern: Focuses on how classes and objects are grouped into large structures. For example,MVC,MVVM, Facade.
  2. Behavioral design Pattern: Focuses on the communication between objects. For example, Delegation (Delegation), Strategy (Strategy), and Observer.
  3. Creational Design Pattern: Focuses on abstracting instantiations of classes. For example, Builder pattern, Singleton pattern, Prototype pattern.

2. Advantages and disadvantages of using design patterns

Advantages:
  1. Design patterns can express solutions to problems in a specific way, reducing the cost of communication between different languages.
  2. The proper use of design patterns can improve the maintainability of code.
  3. The universality of design patterns allows us to quickly apply them to other languages.
Disadvantages:
  1. Design patterns are designed to solve problems in a particular scenario, and overuse can make code less maintainable.
  2. Although design patterns are universal, not all design patterns are, and it is necessary to choose a reasonable design pattern for a particular language.

3. Design patterns that this series will cover

  • The basic design patterns are MVC, Delegation Pattern, Strategy Pattern, Singleton Pattern, Memento Pattern Pattern, Observer Pattern, Builder Pattern
  • Not commonly used design patterns MVVM, Factory Pattern, Adapter Pattern, Iterator Pattern, Prototype Pattern, State Pattern, Multicast Delegate Pattern, Facade Pattern
  • More advanced design patterns include Flyweight Pattern, Mediator Pattern, Composite Pattern, Command Pattern and Chain of Responsibility, Decorator Pattern

See the breakdown below for details.

4. Tool-class diagrams that represent design patterns

You all know the Unified Modeling Language (UML), which is mainly used for modeling and provides visual support for software development. Of course we don’t have to worry about that. We only need to use UML class diagrams to describe design patterns.

1. Description of class diagram

The image above shows that a Dog object has been created.

The hollow arrow represents inheritance, and we usually use Is a for inheritance

SheepDog is a subclass of Dog.

Use solid arrows to indicate the direction of the property.

We can use 1… * denotes a one-to-many relationship. The Farmer has multiple dogs.

Farmer has SheepDog and SheepDog is inherited from Dog.

Prefix the name with << protocol>> to indicate the protocol

Hollow arrows with dotted lines indicate compliance with a protocol.

Farmer kept PetOwning’s agreement.

Above is a complete class diagram. Think about it and look at the picture: There are two subcategories of vehicles, one being cars and the other being vehicles with one or more wheels.

The professor is a teacher and abided by the human agreement.

Class diagram is finished here, is not very simple! So let’s start the body

2. Basic design pattern-MVC

1. Summary of MVC

MVC, the core of the Cocoa framework, divides all classes into three types: Models, Views, and Controllers.

  • Models: Are responsible for holding data, usually structures or classes.
  • Views: Displays elements and Spaces on a screen, usually a subclass of UIView.
  • Controllers: A mediator between models and views, usually a subclass of UIViewController. The relationship between the three: the controller is responsible for managing models and views, and a controller can have multiple models and views. The controller strongly refers to the model and the view. The interaction between the model and the controller is through the property viewer, and the interaction between the view and the controller is through the IBActions. Because controllers are usually responsible for specific business logic, MVC is not that reusable.

Swift Tips: Attribute viewer

   // Attribute viewer
   var s = "whatever" { // s must be a variable
        willSet { // s is called before the new value is set
            print("willSet: ", newValue) / / the new value
        }
        didSet { // is called after the new value is received
            print("didSet: ", oldValue) / / the old value
        }
    }
    s = "hello"
    // willSet: hello
    // didSet: whatever
    
    // Note: willSet and didSet are not called in either case: initialization, changing the value of a variable in didSet

Copy the code

2. The use of MVC

1. Code in the model, including four attributes:
public struct Address {
    public var street: String
    public var city: String
    public var state: String
    public var zipCode: String
}
Copy the code
2. Code in the view:
public final class AddressView: UIView {
    
    @IBOutlet weak var streetTextField: UITextField!
    @IBOutlet weak var cityTextField: UITextField!
    @IBOutlet weak var stateTextField: UITextField!
    @IBOutlet weak var zipCodeTextField: UITextField

    @IBOutlet weak var addressLabel: UILabel!
}
Copy the code

Note: The AddressView replaces the view in the controller, with the benefit that the controller handles only the business logic.

3. Code in controller:
class AddressViewController: UIViewController {
    
    // MARK: - Properties
    public var address: Address? { 
        didSet { // Attribute viewer
            updateViewFromAddress()
        }
    }
    
    public var addressView: AddressView! { / / associated with the view
        guard isViewLoaded else {
            return nil
        }
        return view as! AddressView
    }

    // MARK: - View Lifecycle
    public override func viewDidLoad(a) {
        super.viewDidLoad()
        
    }
    
    private func updateViewFromAddress(a) {
        
        if let address = address {  // Optional type unpack
            addressView.addressLabel.text = "street: "+address.street+"\ncity: "+address.city+"\nstate: "+address.state+"\nzipCode: "+address.zipCode
        }else {
            addressView.addressLabel.text = "Address is empty"}}// MARK: - Actions
    @IBAction public func updateAddressFromView(_ sender: AnyObject) {
        
        guard let street = addressView.streetTextField.text, street.count > 0.let city = addressView.cityTextField.text, city.count > 0.let state = addressView.stateTextField.text, state.count > 0.let zipCode = addressView.zipCodeTextField.text, zipCode.count > 0
            else {
                return
        }
        address = Address(street: street, city: city,
                          state: state, zipCode: zipCode)
    }
    
    @IBAction func clearAddressFromView(_ sender: Any) {
        
        address = nil}}Copy the code

#####4. View of the StroyBoard controller

#####5. Summary The view in the controller is assigned to the view for management. The controller is only responsible for handling the IBAction and its own service logic of the view. The view is updated by listening for changes to the model through the model’s property viewer in the controller.

3. Basic design patterns – Agents

1. Agent Overview

The most common way to describe an agent is to ask someone to do something for us.

The proxy pattern has three parts:

  • Protocol implementation object: the person who does the work for us, and the proxy object calls protocol methods. To avoid circular references, the proxy property needs to be configured with weak.
  • Proxy protocol: defines methods that need to be implemented, which can be optional.
  • Protocol compliance objects: that is, we implement protocol methods by protocol compliance objects. Proxies, like MVC, are used extensively in Cocoa frameworks, most commonly in tableView proxies and data source methods.

2. Use of proxies

1. Agreement Implementer:
class MenuViewController: UIViewController {
    
   weak var delegate: MenuViewControllerDelegate?
    
    @IBOutlet weak var tableView: UITableView! {
        didSet {
            tableView.dataSource = self
            tableView.delegate = self}}let items = ["ITEMS 1"."ITEMS 2"."ITEMS 3"."ITEMS 4"."ITEMS 5"."ITEMS 6"."ITEMS 7"."ITEMS 8"]
    
    override func viewDidLoad(a) {
        super.viewDidLoad()
    }
}

extension MenuViewController: UITableViewDataSource {
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell".for: indexPath) cell.textLabel? .text = items[indexPath.row]return cell
    }
}

extension MenuViewController: UITableViewDelegate {
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){ delegate? .menuViewController(self, didSelectItemAtIndex: indexPath.row, chooseItem: items[indexPath.row])
        
        // Optional chain call. If one method returns nil, the whole chain call failsdelegate? .didSelectItemAtIndex? (indexPath.row)self.navigationController? .popViewController(animated:true)}}Copy the code
2. The agreement:
@objc protocol MenuViewControllerDelegate: class { // Restrict the type of protocol implementation
    
    // The method that must be implemented
    func menuViewController(_ menuViewController: MenuViewController, didSelectItemAtIndex index: Int, chooseItem item: String)
    
    @objc optional func didSelectItemAtIndex(_ index: Int) // Optional method
}
Copy the code
3. Party to the Agreement:
class ViewController: UIViewController {

    @IBOutlet weak var chooseLabel: UILabel!
    
    override func viewDidLoad(a) {
        super.viewDidLoad()
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        guard let viewController = segue.destination as? MenuViewController else { return }
        
        viewController.delegate = self; }}extension ViewController: MenuViewControllerDelegate {
    func menuViewController(_ menuViewController: MenuViewController, didSelectItemAtIndex index: Int, chooseItem item: String) {
        
        chooseLabel.text = item
    }

    func didSelectItemAtIndex(_ index: Int) {   
        print(index)
    }   
}
Copy the code

4. To summarize

This article mainly talks about three contents, how to use class diagram to express the design pattern intuitively, the use of MVC pattern, the use of proxy pattern.

The sample code

Reference:

The Swift Programming Language

The Tao of Objective-C programming

Design Patterns by Tutorials