Skip to content

设计模式

jiaxw32 edited this page Feb 28, 2021 · 6 revisions

什么是设计模式

在软件工程中,设计模式(design pattern)是对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案

设计模式并不直接用来完成代码的编写,而是描述在各种不同情况下,要怎么解决问题的一种方案。面向对象设计模式通常以类别或对象来描述其中的关系和相互作用,但不涉及用来完成应用程序的特定类别或对象。设计模式能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免会引起麻烦的紧耦合,以增强软件设计面对并适应变化的能力

并非所有的软件模式都是设计模式,设计模式特指软件设计层次上的问题。还有其他非设计模式的模式,如架构模式。同时,算法不能算是一种设计模式,因为算法主要是用来解决计算上的问题,而非设计上的问题。

23 种设计模式

《设计模式》一书原先把设计模式分为创建型模式结构型模式行为型模式,把它们通过授权、聚合、诊断的概念来描述。

23种设计模式

创建型模式

模式名称 描述
抽象工厂模式 为一个产品族提供了统一的创建接口。当需要这个产品族的某一系列的时候,可以从抽象工厂中选出相应的系列创建一个具体的工厂类。
工厂方法模式 定义一个接口用于创建对象,但是让子类决定初始化哪个类。工厂方法把一个类的初始化下放到子类。
生成器模式 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
原型模式 用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象。
单例模式 确保一个类只有一个实例,并提供对该实例的全局访问。

结构型模式

模式名称 描述
适配器模式 将某个类的接口转换成客户端期望的另一个接口表示。适配器模式可以消除由于接口不匹配所造成的类兼容性问题。
桥接模式 将一个抽象与实现解耦,以便两者可以独立的变化。
组合模式 把多个对象组成树状结构来表示局部与整体,这样用户可以一样的对待单个对象和对象的组合。
修饰模式 向某个对象动态地添加更多的功能。修饰模式是除类继承外另一种扩展功能的方法。
外观模式 为子系统中的一组接口提供一个一致的界面, 外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
亨元模式 通过共享以便有效的支持大量小颗粒对象。
代理模式 为其他对象提供一个代理以控制对这个对象的访问。

行为型模式

模式名称 描述
责任链模式 为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它。
命令模式 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可取消的操作。
解释器模式 给定一个语言, 定义它的文法的一种表示,并定义一个解释器, 该解释器使用该表示来解释语言中的句子。
迭代器模式 提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。
中介者模式 包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用,从而使它们可以松散偶合。当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用,保证这些作用可以彼此独立的变化。
备忘录模式 备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捉住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。
观察者模式 在对象间定义一个一对多的联系性,由此当一个对象改变了状态,所有其他相关的对象会被通知并且自动刷新。
状态模式 让一个对象在其内部状态改变的时候,其行为也随之改变。状态模式需要对每一个系统可能获取的状态创立一个状态类的子类。当系统的状态变化时,系统便改变所选的子类。
策略模式 定义一个算法的系列,将其各个分装,并且使他们有交互性。策略模式使得算法在用户使用的时候能独立的改变。
模版方法模式 模板方法模式准备一个抽象类,将部分逻辑以具体方法及具体构造子类的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。先构建一个顶级逻辑框架,而将逻辑的细节留给具体的子类去实现。
访问者模式 封装一些施加于某种数据结构元素之上的操作。一旦这些操作需要修改,接受这个操作的数据结构可以保持不变。访问者模式适用于数据结构相对未定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由的演化。

代理模式

代理模式概述

代理模式(英语:Proxy Pattern)是指为其他对象提供一个代理以控制对这个对象的访问。

所谓的代理者是指一个类别可以作为其它东西的接口。代理者可以作任何东西的接口:网络连接、存储器中的大对象、文件或其它昂贵或无法复制的资源。

当一个复杂对象的多份副本须存在时,代理模式可以结合享元模式以减少存储器用量。典型作法是创建一个复杂对象及多个代理者,每个代理者会引用到原本的复杂对象。而作用在代理者的运算会转送到原本对象。一旦所有的代理者都不存在时,复杂对象会被移除。

代理模式用 UML 图表示如下:

proxy pattern

  • 继承关系:空心三角 + 实线表示
  • 关联关系:用实线箭头表示
  • 依赖关系:用虚线箭头表示

代理模式使用场景

  • 远程代理:为一个对象在不同的地址空间提供局部代表,这样可以隐藏一个对象存在于不同地址空间的事实。
  • 虚拟代理:根据需要创建开销很大的对象,通过它来存放实例化需要很长时间的真实对象。
  • 安全代理:用来控制真实对象访问时的权限
  • 智能指引:是指当调用真实的对象时,代理处理另外一些事

上述应用场景摘自《大话设计模式》一书

示例

以下Java示例解释"虚拟代理"模式。ProxyImage 类别用来访问远程方法。

import java.util.*;
 
interface Image {
    public void displayImage();
}

//on System A 
class RealImage implements Image {
    private String filename;
    public RealImage(String filename) { 
        this.filename = filename;
        loadImageFromDisk();
    }

    private void loadImageFromDisk() {
        System.out.println("Loading   " + filename);
    }

    public void displayImage() { 
        System.out.println("Displaying " + filename); 
    }
}

//on System B 
class ProxyImage implements Image {
    private String filename;
    private Image image;
 
    public ProxyImage(String filename) { 
        this.filename = filename; 
    }
    public void displayImage() {
        if(image == null)
              image = new RealImage(filename);
        image.displayImage();
    }
}
 
class ProxyExample {
    public static void main(String[] args) {
        Image image1 = new ProxyImage("HiRes_10MB_Photo1");
        Image image2 = new ProxyImage("HiRes_10MB_Photo2");     
        
        image1.displayImage(); // loading necessary
        image2.displayImage(); // loading necessary
    }
}

观察者模式

观察者模式概述

观察者模式是软件设计模式的一种。在此种模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实时事件处理系统。(维基百科定义)

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。(《设计模式》一书定义)

观察者模式 UML 图

Observer pattern

Python 示例

class AbstractSubject(object):
    def register(self, listener):
        raise NotImplementedError("Must subclass me")
 
    def deregister(self, listener):
        raise NotImplementedError("Must subclass me")
 
    def notify_listeners(self, event):
        raise NotImplementedError("Must subclass me")
 
class Listener(object):
    def __init__(self, name, subject):
        self.name = name
        subject.register(self)
 
    def notify(self, event):
        print self.name, "received event", event
 
class Subject(AbstractSubject):
    def __init__(self):
        self.listeners = []
        self.data = None

    def getUserAction(self):
        self.data = raw_input('Enter something to do:')
        return self.data

    # Implement abstract Class AbstractSubject

    def register(self, listener):
        self.listeners.append(listener)
 
    def deregister(self, listener):
        self.listeners.remove(listener)
 
    def notify_listeners(self, event):
        for listener in self.listeners:
            listener.notify(event)

 
if __name__=="__main__":
    # make a subject object to spy on
    subject = Subject()
 
    # register two listeners to monitor it.
    listenerA = Listener("<listener A>", subject)
    listenerB = Listener("<listener B>", subject)
 
    # simulated event
    subject.notify_listeners ("<event 1>")
    # outputs:
    #     <listener A> received event <event 1>
    #     <listener B> received event <event 1>
 
    action = subject.getUserAction()
    subject.notify_listeners(action)
    #Enter something to do:hello
    # outputs:
    #     <listener A> received event hello
    #     <listener B> received event hello

C# 示例

using System;
using System.Collections;

namespace Wikipedia.Patterns.Strategy
{
	// IObserver --> interface for the observer
    public interface IObserver
	{
		// called by the subject to update the observer of any change
		// The method parameters can be modified to fit certain criteria
		void Update(string message);
	}

	public class Subject
	{
		// use array list implementation for collection of observers
		private ArrayList observers;

		// constructor
		public Subject()
		{
			observers = new ArrayList();
		}

		public void Register(IObserver observer)
		{
			// if list does not contain observer, add
			if (!observers.Contains(observer))
			{
				observers.Add(observer);
			}
		}

		public void Deregister(IObserver observer)
		{
			// if observer is in the list, remove
			if (observers.Contains(observer))
			{
				observers.Remove(observer);
			}
		}

		public void Notify(string message)
		{
			// call update method for every observer
			foreach (IObserver observer in observers)
			{
				observer.Update(message);
			}
		}
	}

	// Observer1 --> Implements the IObserver
	public class Observer1 : IObserver
	{
		public void Update(string message)
		{
			Console.WriteLine("Observer1:" + message);
		}
	}

	// Observer2 --> Implements the IObserver
	public class Observer2 : IObserver
	{
		public void Update(string message)
		{
			Console.WriteLine("Observer2:" + message);
		}
	}

	// Test class
	public class ObserverTester
	{
		[STAThread]
		public static void Main()
		{
			Subject mySubject = new Subject();
			IObserver myObserver1 = new Observer1();
			IObserver myObserver2 = new Observer2();

			// register observers
			mySubject.Register(myObserver1);
			mySubject.Register(myObserver2);

			mySubject.Notify("message 1");
			mySubject.Notify("message 2");
		}
	}
}

单例模式

单例模式概述

单例模式,也叫单子模式,属于创建型模式的一种。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。

实现单例模式的思路是:一个类能返回对象一个引用(永远是同一个)和一个获得该实例的方法(必须是静态方法,通常使用getInstance这个名称);当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用;同时我们还将该类的构造函数定义为私有方法,这样其他处的代码就无法通过调用该类的构造函数来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例。

OC 单例实现

@interface Singleton : NSObject

+(Singleton*)sharedInstance;

@end


@implementation Singleton

static Singleton *sharedSingleton = nil;

+(Singleton*)sharedInstance {
    static dispatch_once_t token;
    dispatch_once(&token, ^{
        if(sharedSingleton == nil){
            sharedSingleton = [[self alloc] init];
        }
    });
    return sharedSingleton;
}

/*
 overrides the allocWithZone: method to ensure that another instance is not allocated 
 if someone tries to allocate and initialize an instance of your class directly 
 instead of using the class factory method. Instead, it just returns the shared object.
 */
+(id)allocWithZone:(struct _NSZone *)zone {
   static dispatch_once_t token;
    dispatch_once(&token, ^{
        if(sharedSingleton == nil) {
            sharedSingleton = [super allocWithZone:zone];
        }
    });
    return sharedSingleton;
}

- (id)copy {
    return self;
}

- (id)mutableCopy {
    return self;
}

@end

参考资料

Clone this wiki locally