这是我参与「第四届青训营 」笔记创作活动的第7天
设计模式(上)
OOP七大原则
- 开闭原则:添加新功能只能添加新代码不要修改原内容
- 里氏替换原则:子类值扩展父类功能,不要改变父类的原功能
- 依赖导致原则:抽象不依赖细节,细节应该依赖抽象,面向接口编程而不是面向实现编程,以降低程序之间的耦合性
- 单一职责原则:一个对象尽量只做一件事,以控制类的粒度大小,提高其内聚性
- 接口隔离原则:要为各个类建立其专用接口
- 迪米特法则:两个对象之间不要直接沟通,尽量用第三方转发来沟通(get、set)
- 合成复用原则:尽量先使用组合或聚合等关联来实现,其次才考虑用继承关系实现
创建型模式
单例模式
- 用处:多个线程同时操作一个文件时,就必须在同个实例上进行
- 做法:将构造器私有,所以每次调用都是同一个实例
-
饿汉式单例
- 优点:线程安全,实现简单,没加锁所以效率高
- 缺点:类被加载时就会初始化,造成空间浪费,易产生垃圾对象
- 例:
public class HungryMan { private static HungryMan hungryMan = new HungryMan(); private HungryMan(){ } public static HungryMan getInstance(){ return hungryMan; } } -
懒汉式单例
- 优点:第一次调用时才会初始化,避免浪费内存
- 缺点:不加锁的时候线程不安全,但加了锁线程效率太低
- 例:
public class LazyMan { private static LazyMan lazyMan; private LazyMan(){} public static synchronized LazyMan getInstance(){ if(lazyMan == null){ lazyMan = new LazyMan(); } return lazyMan; } } -
双重检测锁的懒汉式单例模式(DCL,即 double-checked locking)
- 优点:多线程时还能保持高性能
- 缺点:可以被反射破坏,会面临反射破坏问题
- 例:
private volatile static LazyMan lazyMan; public static LazyMan getInstance(){ if(lazyMan == null){ synchronized (LazyMan.class){//双重锁 if(lazyMan == null){ lazyMan = new LazyMan(); } } } return lazyMan; }
工厂模式
-
作用:实现了创建者和调用者的分离
-
原理:
- 实例化对象不再使用new而是使用工厂方法。
- 创建对象时不会对客户端暴露创建逻辑
- 用户只需要告诉工厂即可获得实例,而不需要自己去设置参数
-
简单工厂模式
- 原理:多个同等级结构的类继承同个接口,简单工厂可以生产这几个类的实例
- 流程:用户传入指令给工厂,工厂根据指令将类实例化后返回给用户
- 缺点:增加新类时需要改变工厂类的代码,不符合开闭原则
- ps:由于工厂内的方法都是静态方法,故又称静态工厂模式
-
工厂方法模式
- 原理:多个类继承同个接口后,每个类有独自的工厂
- 流程:用户调用想要的类的工厂以获得目标类的实例
- 例:
Car car = new CarWuling().getCar();
- 例:
- 优点:符合OPP七大原则,在设计模式上更科学合理
- 缺点:代码量太大,故实际开发上简单工厂模式更常用
-
抽象工厂模式
- 定义:抽象工厂提供了一个创建一系列相关或者相互依赖对象的结构,无需制定他们的具体类
- 解释:抽象工厂就是工厂的工厂(加一层)
- 原理:用一个超级工厂创建其他工厂
//超级工厂 public interface SuperFactory { Phone phoneFactory(); Router routerFactory(); }//品牌 public class HuaweiFactory implements SuperFactory { @Override public Phone phoneFactory() { return new Phone(); } @Override public Router routerFactory() { return new Router(); } }
建造者模式
- 定义:将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示
- 作用:用户只需要给定复杂对象的类型和内容,建造者就会按顺序创建复杂对象,从而把内部的建造过程和细节隐藏起来
- 关系:
- 建造者:创建和提供实例
- 指挥者:管理建造出来的实例的依赖关系。
- 原理:用户实例化建造者,用指挥者控制建造者建造的顺序
- 应用场景:需要生成的产品中有复杂的内部结构
- 例:
- 产品:
public class Product { private String a; private String b; public String getA() { return a; } public void setA(String a) { this.a = a; } public String getB() { return b; } public void setB(String b) { this.b = b; } }- 建造者抽象类
public interface Worker { public void setA(); public void setB(); public Product getPhone(); }- 建造者
public class Builder implements Worker { private Product product; public Builder() { product = new Product(); } @Override public void setA() { product.setA("aaa"); } @Override public void setB() { product.setB("bbb"); } @Override public Product getPhone() { return product; } }- 指挥者
public class Director { public Product create(Builder builder){ builder.setA(); builder.setB(); return builder.getPhone(); } }- 用户
public class TestBuilder { public static void main(String[] args) { Director director = new Director(); Builder builder = new Builder(); Product product = director.create(builder); } }