goF23设计模式~思想学习笔记(二)
goF23设计模式~思想学习笔记(三)
设计模式-终身学习
前言
你是否早已领会到,时间少、开发任务重,草草了事完成功能开发,原型变动版本迭代,相当于推翻重来,一个类的变动导致很多地方都得跟着调整,一不小心漏了一种情况,测试难覆盖,导致悲剧产生呢。那是因为你在开发中针对问题没有使用更优雅的方案解决--设计模式,不是老生常谈,而是每次都是新收获,经典就是这样不会过时,希望你带着空杯的心态慢慢领悟,主要是思想的提升,为什么这么写优雅(有时代码量反而多了);把变和不变的东西搞清楚,哪些需要抽象。设计模式是很必要我们投入时间和精力学习的,一段时间后再看就会不一样了。
本笔记是观看该视频的笔记和感悟,逻辑一致代码跟随演练,部分代码简化处理包含UML类,设计模式是前辈门在软件工程总结的经验和是解决问题的方案,贵在思想领悟,实际的开发框架中使用的可能是此教程设计模式的变种,但万变不离其宗,本笔记记录的是标准写法。想要学好设计模式需要先弄清其原理,多思考总结,才能更好吸收。如有不对的地方请赐教,我们一起学习成长。
你可能会问既然有视频了为啥还有会这个笔记呢,我去看视频好了,笔记是我的学习总结(写给自己和需要的人),视频时间很有点长,我笔记会记录核心逻辑,不清晰的可以看视频,或者以后,用来查阅。同样我也非常赞成你和我一样学完后,整理出学习笔记。笔记不仅仅是写给他人更是写给自己的(《高效学习》-教就是最好的学)。
GoF23设计模式
B站视频链接
全套代码地址 https://gitee.com/zhuyunjiandull/design_pattern
设计模式的六大原则
原则 | 解释 |
---|---|
单一原则 (SRP | 一个类只做一件事 |
开放-封闭原则(OCP | 软件实体(类、模块、函数)可以拓展,但是不可修改 |
依赖倒转原则(DIP) | A.高层模块不应该依赖底层,两个都应该依赖抽。B.抽象不应该依赖细节,细节依赖抽象 |
里氏代换原则(LSP) | 子类型必须能够替换掉它们的父类型 |
迪米特法则(LoD) | 如果两个类不必直接通信,那么这两个类不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可通过第三者发起这个调用 |
合成/聚合复用原则(CARP) | 尽量使用合成/聚合,尽量不要使用类继承 |
分类和特性
经典设计模式大方向分为三大类,创建型模式、结构型模式、行为型模式。创建型模式里面包含5个,结构型模式包含7个,行为型模式包含11个。
创建型模式:主要用于处理对象的创建,实例化对象。但是,这可能会限制在系统内创建对象的类型或数目。
结构型模式:处理类或对象间的组合。它将以不同的方式影响着程序,允许在补充写代码或自定义代码的情况下创建系统,而且具有重复使用性和应用性能。
行为型模式:描述类或对象怎样进行交互和职责分配。影响系统的状态、行为流,简化、优化并且提高应用程序的可维护性。
创建型模式
- 单例模式
- 工厂方法模式
- 抽象工厂模式
- 建造者模式
- 原型模式
结构型模式
- 适配器模式
- 装饰器模式
- 代理模式
- 外观模式
- 桥接模式
- 组合模式
- 享元模式
行为型模式
- 模板方法模式
- 观察者模式
- 迭代子模式
- 责任链模式
- 命令模式
- 备忘录模式
- 状态模式
- 访问者模式
- 中介者模式
- 解释器模式
- 策略模式
如何合理的选择该用什么样的设计模式?
创建型模式
单例模式(Singleton Pattern): 保证一个类仅有一个实例,并提供一个访问它的全局访问点。
工厂方法模式(Factory Method Pattern): 定义一个用于创建对象的接口,让子类决定将哪一个类实例化。Factory Method使一个类的实例化延伸到其子类。
抽象工厂模式(Abstract Factory Pattern): 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
建造者模式(Builder Pattern): 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
原型模式(Prototype Pattern): 用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。
结构型模式
适配器模式(Adapter Pattern): 将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
装饰模式(Decorator Pattern): 动态地给一个对象添加一些额外的职责。就扩展功能而言,它比生成子类方式更为灵活。
代理模式(Proxy Pattern): 为其他对象提供一个代理以控制对这个对象的访问。
外观模式(Facade Pattern): 为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
桥接模式(Bridge Pattern): 将抽象部分与它的实现部分分离,使它们都可以独立地变化。
组合模式(Composite Pattern): 将对象组合成树形结构以表示“部分-整体”的层次结构。它使得客户对单个对象和复合对象的使用具有一致性。
享元模式(Flyweight Pattern): 运用共享技术有效地支持大量细粒度的对象。
行为型模式
模板方法模式(Template Method Pattern): 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
责任链模式(Chain of Responsibility Pattern): 为解除请求的发送者和接收者之间耦合,而使多个对象都有机会处理这个请求。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它。
解释器模式(Interpreter Pattern): 给定一个语言,定义它的文法的一种表示,并定义一个解释器, 该解释器使用该表示来解释语言中的句子。
观察者模式(Observer Pattern): 定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动刷新。
迭代器模式(Iterator Pattern): 提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。
命令模式(Command Pattern): 将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可取消的操作。
备忘录模式(Memento Pattern): 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到保存的状态。
状态模式(State Pattern): 允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它所属的类。
访问者模式(Visitor Pattern): 表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
中介者模式(Mediator Pattern): 用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
策略模式(Strategy Pattern): 定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法的变化可独立于使用它的客户。
类图关系箭头和线说明
核心思想分析领悟
创建型模式
1. 单例模式
//1.饿汉式:静态常量 特点:类装载创建,可能会浪费内存
class SingletonHungry {
//1.私有化构造
private SingletonHungry(){}
//2.类内部创建对象
private final static SingletonHungry instance = new SingletonHungry();
//3.对外提供获取实例方法
public static SingletonHungry getInstance() {
return instance;
}
}
//2.懒汉式线程不安全,
class SingletonLazy {
//1.私有化构造
private SingletonLazy(){}
//2.类内部创建对象
private static SingletonLazy instance;
//3.对外提供获取实例方法
public static SingletonLazy getInstance() {
if(instance==null){
instance = new SingletonLazy();
}
return instance;
}
}
//2.2懒汉式 特点:线程安全同步写法,效率低,
class SingletonLazy2 {
//1.私有化构造
private SingletonLazy2(){}
//2.类内部创建对象
private static SingletonLazy2 instance;
//3.对外提供获取实例方法
public static synchronized SingletonLazy2 getInstance() {
if(instance==null){
instance = new SingletonLazy2();
}
return instance;
}
}
//3 双重检测
class SingletonDoubleCheck {
//1.私有化构造
private SingletonDoubleCheck() {}
//2.类内部创建对象
private static volatile SingletonDoubleCheck instance;
//3.对外提供获取实例方法
public static SingletonDoubleCheck getInstance() {
if (instance == null) {
synchronized (SingletonDoubleCheck.class) {
if (instance == null) {
instance = new SingletonDoubleCheck();
}
}
}
return instance;
}
}
//4.静态内部类
class SingletonStaticClass {
//1.私有化构造
private SingletonStaticClass() {}
//2.内部类
private static class SingletonInstance {
private static final SingletonStaticClass INSTANCE = new SingletonStaticClass();
}
//3.对外提供获取实例方法
public static SingletonStaticClass getInstance() {
return SingletonInstance.INSTANCE;
}
}
//5.枚举
enum SingleEnum {
INSTANCE;
public void method(){
}
}
public class SingletonTest {
public static void main(String[] args) {
// SingletonHungry creation.singleton = SingletonHungry.getInstance();
// System.out.println(creation.singleton);
// SingletonHungry singleton2 = SingletonHungry.getInstance();
// System.out.println(singleton2);
// System.out.println(creation.singleton==singleton2);
System.out.println(SingletonDoubleCheck.getInstance());
System.out.println(SingleEnum.INSTANCE);
}
}
2. 工厂模式 : 通过外部参数直接获取想要的对象实例,实例初始化步骤放到 OrderPizza 内部
2.1 不使用设计模式
public class OrderPizza {
Pizza getPizza(String name){
Pizza pizza = null;
switch (name){
case "chess":
pizza = new ChessPizza();
break;
case "greek":
pizza = new GreekPizza();
break;
}
if(pizza != null){
pizza.prepare();
pizza.baker();
pizza.cut();
pizza.box();
}
return pizza;
}
}
缺点:无工厂增加一个种类 需要需改 OrderPizza不符合开闭原则
2.2 简单工厂 改进方案
//工厂类 增加种类只需要修改工厂类SimpleFactory 业务类OrderPizza不需要修改
public class SimpleFactory {
static Pizza getPizza(String name){
Pizza pizza = null;
switch (name){
case "chess":
pizza = new ChessPizza();
break;
case "greek":
pizza = new GreekPizza();
break;
}
return pizza;
}
}
//业务
public class OrderPizza {
Pizza orderPizza(String name){
Pizza pizza = SimpleFactory.getPizza(name);
if(pizza != null){
pizza.prepare();
pizza.baker();
pizza.cut();
pizza.box();
}
return pizza;
}
}
2.3 工厂方法 : 定义一个用于创建对象的接口,让子类决定将哪一个类实例化。Factory Method使一个类的实例化延伸到其子类。
enum OrderType {
bJType,
lDType
}
class OrderPizza {
Pizza createPizza(OrderType orderType,String name){
Pizza pizza = null;
if(orderType==OrderType.bJType){
pizza = new BJOrderPizza().orderPizza(name);
}else if(orderType==OrderType.lDType) {
pizza = new LDOrderPizza().orderPizza(name);
}
if(pizza != null){
pizza.prepare();
pizza.baker();
pizza.cut();
pizza.box();
}
return pizza;
}
}
class BJOrderPizza {
Pizza orderPizza(String name){
Pizza pizza = null;
switch (name){
case "chess":
pizza = new BJChessPizza();
break;
case "greek":
pizza = new BJGreekPizza();
break;
}
return pizza;
}
}
class LDOrderPizza {
Pizza orderPizza(String name){
Pizza pizza = null;
switch (name){
case "chess":
pizza = new LDChessPizza();
break;
case "greek":
pizza = new LDGreekPizza();
break;
}
return pizza;
}
}
3. 抽象工厂 :提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
public class OrderPizza extends Object{
Pizza orderPizza(AbFactory factory, String name){
Pizza pizza = factory.createPizza(name);
if(pizza != null){
pizza.prepare();
pizza.baker();
pizza.cut();
pizza.box();
}
return pizza;
}
}
public class Test {
public static void main(String[] args) {
//抽象工厂方法
OrderPizza orderPizza = new OrderPizza();
orderPizza.orderPizza(new BJFactory(),"chess");
orderPizza.orderPizza(new BJFactory(),"greek");
orderPizza.orderPizza(new LDFactory(),"chess");
orderPizza.orderPizza(new LDFactory(),"greek");
}
}
4. 建造者: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
public class HouseDirector {
private HouseBuilder builder;
public HouseDirector(HouseBuilder builder) {
this.builder = builder;
}
//指挥 建造流程
House buildHouse(){
builder.buildBasic();
builder.buildWall();
builder.buildRoof();
return builder.getHouse();
}
}
abstract public class HouseBuilder {
//创建产品
protected House house = new House();
//创建行为定义
public abstract void buildBasic();
public abstract void buildWall();
public abstract void buildRoof();
public House getHouse() {
return house;
}
}
public class ComHouse extends HouseBuilder {
private String name = "ComHouse ";
@Override
public void buildBasic() {
String s = name + "打地基";
house.setBasic(s);
System.out.println(s);
}
@Override
public void buildWall() {
String s = name + "砌墙";
house.setWall(s);
System.out.println(s);
}
@Override
public void buildRoof() {
String s = name + "盖屋顶";
house.setRoof(s);
System.out.println(s);
}
}
5. 原型模式:用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。
public class Video implements Cloneable,Serializable{
private String name;
private Date data;
public Video(String name, Date data) {
this.name = name;
this.data = data;
}
@Override
protected Object clone() throws CloneNotSupportedException {
var obj = (Video) super.clone();
obj.data = (Date) data.clone();
return obj;
}
protected Object deepClone() {
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
Object obj = null;
try {
//序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
obj = ois.readObject();
}catch (Exception e){
System.out.println(e);
}finally {
try {
bos.close();
oos.close();
bis.close();
ois.close();
}catch (Exception e){
System.out.println(e);
}
}
return obj;
}
public void setData(Date data) {
this.data = data;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Video{" +
"name='" + name + '\'' +
", data=" + data +
'}';
}
}