• 设计模式笔记1


    前言:

    1. 了解OO并不一定能设计出好的系统,设计模式实际上是一些构建OO系统的隐藏经验,可以在构建系统时提供一个大致的思路。所以,要辩证的看设计模式,不能迷信,也不能不信。

    2. 本文使用的开发语言为java,只涉及设计模式的基本思想,并不深究java的语法和设计。

    本文主要介绍:策略模式,观察者模式,装饰模式以及工厂模式。

    策略模式

    策略模式定义了算法族,分别封装起来,让他们之间可以互相替换,此模式可以让算法的变化独立于使用算法的客户。

    注意:

    • 区分is-a(继承),has-a(组合:使用多个类)以及实现(implements)
    • 多用组合,少用继承,优点是不仅可以将算法聚合成类,还可以在运行时动态改变行为。
    • 如《Head First》所说,面向接口编程实际上指的是面向超类型编程,这里的接口不单单指Java中的interface,关键在于利用多态对超类型编程,更具体来说,声明一个类的时候不必理会以后执行时的真正类型。

    总的来说,就是尽可能分离出is-a,has-a,has-a尽可能通过接口或者抽象类实现,避免通过继承实现导致不能cover住整体的调整。

    而且可以通过组合和委托来实现运行时动态扩展的效果。

    (我知道自己这段写的不像人话,水平所限,暂时没啥好的表述。。。)

    观察者模式

    在对象之间定义一种一对多的依赖,这样当一个对象改变状态,依赖他的对象都会收到通知,并自动更新。

    直观来说,就是一种发布订阅模式,不过到底是pull还是push不确定。一个典型的观察者模式是一个发布者对应多个订阅者,发布者的某些状态改变后,向订阅者发送通知,同步变化。

    具体实现上,可以自己手写也可以通过java.util.Observer和Observable实现,当然在java9之后的版本中Observer相关的实现被废弃了,详细原因有很多,可自行百度。针对这种情况,java包也提供了相应的替代方法,例如java.beans.PropertyChangeEvent以及java.util.concurrent.Flow等。

    装饰者模式

    一个关键的设计原则是:类应该对扩展开放,对修改关闭。 也叫做开放-关闭原则。装饰者模式中这种原则表现的非常明显,实际上,这种思想在策略模式以及观察者模式中也有一定体现。

    直观理解:装饰者模式也可以形象地理解为“套娃模式”,需要一层层的剥开,每一层就是一个装饰器,这样可以在尽可能不影响类实现的基础上扩展功能。

    关键要点:

    1. +装饰者和被装饰者都继承自一个超类;
    2. +装饰者需要在实现时实例化一个组件,并包含在装饰者内部;
    3. -装饰者模式会不可避免的带来一些小类,很难快速了解整体设计模式思路。

    工厂模式

    与其说是一种设计模式,常见的简单工厂更像一个编程习惯。因为简单工厂非常常见,所以掌握这部分也是非常重要的。一种简单工厂的代码示例如下(一个Head First中关于Pizza的例子):

    public class SimpleFactory {
        public Pizza create(String type) {
        	Pizza p = null;
        	if (type.equals("cheese")) p = new CheesePizza();
        	return p;
    	}
    }
    
    public abstract class Pizza {
    	// something
    }
    
    public class CheesePizza extends Pizza {
    	// something
    }
    
    public class PizzaStore {
    	SimpleFactory sf = new SimpleFactory();
    	public Pizza orderPizza(String type) {
    		Pizza p = null;
    		p = sf.create(type);
    		// do something
    		return p;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    有的时候,把全部的实现都放在工厂里并不是一个好的选择,因为这样失去了一定的弹性,因此我们可以把PizzaStore中的简单工厂替换掉,允许子类做决定。下面是一个例子:

    public abstract class PizzaStore {
    
    	public Pizza orderPizza(String type) {
    		Pizza p = null;
    		p = createPizza(type);
    		p.prepare();
    		p.bake();
    		p.cut();
    		p.box();
    		return p;
    	}
    	
    	protected abstract Pizza createPizza(String type); 
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    好处是各种继承PizzaStore的商店可以自行决定如何提供什么样的Pizza。一种工厂方法的范式如下:

    abstract Product factoryMethod(String type)
    
    • 1

    工厂模式的类图如下:

    继承
    继承
    多元关联
    Creator
    +factoryMethod()
    +OneOperation()
    Product
    ConcreteCreator
    +factoryMethod()
    ConcreteProduct

    可以发现PizzaStore的具体行为,实际上是通过Pizza的具体种类决定的,同时而且无需知道Pizza的具体种类,也就是说,PizzaStore和各种Pizza的子类通过Pizza这个抽象解耦合,通过这种方式,PizzaStore减少了对具体Pizza类的依赖,具体Pizza类也在依赖相对高层的Pizza抽象。因此在此提出了著名的“依赖倒置”原则。

    一些指导方针有助于尽可能少的违反依赖倒置原则:

    • 变量不可以持有具体类的引用;(说人话,不要在类里使用new,new工厂除外)
    • 不要让类派生自具体类;(就是所有的类要派生自抽象类或者接口)
    • 不要覆盖基类中实现的方法。(如果非要这样,那么这个基类的抽象就是失败的,基类中的方法应该是由子类共享的)

    当然,不必完全遵守,尽可能遵守即可。

    抽象工厂:提供一个接口,用于创建相关或者依赖对象的家族,而无需明确指定具体类。(在具体工厂上更进一步进行抽象)

  • 相关阅读:
    OpenResty介绍及实现限流
    数字孪生园区场景中的坐标知识
    软件功能点估算
    C 基础语法3 —— 指针
    多线程顺序运行的 4 种方法,面试随便问
    Java基础面试题【1】
    商业智能BI
    【软件测试】 1+X初级 功能测试试题
    【华为机试真题 JAVA】一种字符串压缩表示的解压-100
    springboot实现WebAPI版本控制
  • 原文地址:https://blog.csdn.net/qwq_wot/article/details/125521622