Gang of Four(四人帮)在《设计模式:可复用面向对象软件的基础》一书中提出了23种设计模式,分为创建型模式、结构型模式和行为型模式,其中创建型模式5种,结构性模式7种,行为型模式11种:
模式 | 介绍 |
---|---|
工厂方法模式 | 定义一个用于创建对象的接口,让子类决定创建哪种对象。 |
抽象工厂模式 | 提供一个创建一系列相关或相互依赖对象的接口。 |
单例模式 | 确保一个类只有一个实例。 |
原型模式 | 通过克隆已有对象来创建新对象。 |
建造者模式 | 将一个复杂对象的创建过程分解成多个步骤,从而使创建过程更加灵活。 |
模式 | 介绍 |
---|---|
适配器模式 | 将一个类的接口转换成另一个类需要的接口。 |
装饰器模式 | 动态地将职责附加到对象上。 |
代理模式 | 为另一个对象提供一个代理,以控制对该对象的访问。 |
外观模式 | 为一个复杂系统提供一个简单的接口。 |
桥接模式 | 将抽象与实现分离。 |
组合模式 | 将对象组织成树形结构。 |
享元模式 | 运用共享技术有效地支持大量细粒度对象的复用。 |
模式 | 介绍 |
---|---|
策略模式 | 定义一系列算法,并让客户可以选择其中一个算法。 |
模板方法模式 | 定义一个操作的骨架,而将一些步骤延迟到子类中实现。 |
观察者模式定 | 义了一种对象之间的一对多依赖关系,以便当一个对象的状态发生改变时,所有依赖它的对象都会得到通知。 |
迭代器模式 | 提供一种方法来访问一个聚合对象的各个元素,而无需暴露该对象的内部表示。 |
责任链模式 | 请求沿着一个由处理者组成的链传递,直到找到合适的处理者来处理该请求。 |
命令模式 | 将一个请求封装为一个对象,从而使您可以用不同的方式来参数化请求、队列化请求或记录请求。 |
备忘录模式 | 保存一个对象的内部状态,以便以后恢复该状态。 |
状态模式 | 根据对象的内部状态改变其行为。 |
访问者模式 | 定义一个对象遍历另一个对象的结构,并在遍历过程中执行操作。 |
中介者模式 | 用一个中介对象来封装一系列对象的交互。 |
解释器模式 | 定一个语言,定义它的文法的一种表示,并定义一个解释器来解释该表示。 |
在平时的业务开发中,其实真正使用设计模式的场景并不多,虽然有23种之多,但是在项目最常使用的也就几种而已,重点的是:在什么业务场景下使用了设计模式,什么设计模式?
所谓的单例设计指的是一个类只允许产生一个实例化对象,最好理解的一种设计模式,分为饿汉式和懒汉式。单例对象能节约系统资源,一个对象的创建和消亡的开销可能很小。但是日常的服务接口,就算是一般小公司也有十几万的QPS吧。每一次的功能运转都创建新的对象来响应请求,十几万对象的创建和销毁,想想就是一笔大开销,所以 spring 管理构造的 bean 对象一般都是单例。而且单例模式可以更好的解决并发的问题,方便实现数据的同步性。
优点
缺点
饿汉式:构造方法私有化,外部无法产生新的实例化对象,只能通过static方法取得实例化对象
class Singleton {
/**
* 在类的内部可以访问私有结构,所以可以在类的内部产生实例化对象
*/
private static Singleton instance = new Singleton();
/**
* private 声明构造
*/
private Singleton() {
}
/**
* 返回对象实例
*/
public static Singleton getInstance() {
return instance;
}
public void print() {
System.out.println("Hello Singleton...");
}
}
懒汉式:当第一次去使用Singleton对象的时候才会为其产生实例化对象的操作
class Singleton {
/**
* 声明变量
*/
private static volatile Singleton singleton = null;
/**
* 私有构造方法
*/
private Singleton() {
}
/**
* 提供对外方法
* @return
*/
public static Singleton getInstance() {
// 还未实例化
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
public void print() {
System.out.println("Hello World");
}
}
当多个线程并发执行 getInstance 方法时,懒汉式会存在线程安全问题,所以用到了 synchronized 来实现线程的同步,当一个线程获得锁的时候其他线程就只能在外等待其执行完毕。而饿汉式则不存在线程安全的问题。
实例化对象不是用new,用工厂方法替代,使用者不关心对象的实例化过程,只关心对象的获取。将选择实现类,创建对象统一管理和控制。从而将调用者跟我们的实现类解耦。
优点
缺点
用来生产同一等级架构中的任意产品(对于增加新的产品,需要修改已有代码),在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例。简单工厂不是一种设计模式,反而比较像是一种编程习惯。
接下来创建一个接口,两个实现类,一个工厂,一个测试类
//创建手机接口
public interface Phone {
void name();
}
//创建华为实现类
public class HuaWei implements Phone{
@Override
public void name() {
System.out.println("华为手机");
}
}
//创建小米实现类
public class XiaoMi implements Phone{
@Override
public void name() {
System.out.println("小米手机");
}
}
//创建工厂
public class PhoneFactory {
public static Phone getPhone(String phone){
if(phone.equals("华为")){
return new HuaWei();
}else if(phone.equals("小米")){
return new XiaoMi();
}else {
return null;
}
}
}
//测试类
public class Consumer {
public static void main(String[] args) {
Phone p1= PhoneFactory.getPhone("华为");
Phone p2= PhoneFactory.getPhone("小米");
p1.name();
p2.name();
}
}
得到测试结果
华为手机
小米手机
我们通过创建一个PhoneFactory类,成功的完成工厂的创建。我们在创建对象时,也就不需要直接创建对象,而是可以通过创建工厂,这样大大的降低了代码的耦合性。但是,静态工厂模式是不能添加数据的。比如说,我们想添加一个“Oppo”手机类,你不直接修改PhoneFactory工厂代码,是不能实现的。所以,就有了第二种的工厂方法模式。
用来生产同一等级架构中的固定产品,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建 。(支持增加任意产品)
//创建手机接口
public interface Phone {
void name();
}
//创建华为实现类
public class HuaWei implements Phone{
@Override
public void name() {
System.out.println("华为手机");
}
}
//创建手机工厂接口
public interface PhoneFactory {
Phone getPhone();
}
//创建华为工厂
public class HuaWeiFactory implements PhoneFactory{
@Override
public Phone getPhone() {
return new HuaWei();
}
}
//测试类
public class Consumer {
public static void main(String[] args) {
Phone phone = new HuaWeiFactory().getPhone();
phone.name();
}
}
得到测试结果
华为手机
我们创建了手机工厂接口PhoneFactory,再创建华为工厂HuaWeiFactory实现工厂,这样就可以通过HuaWeiFactory创建对象。增加新的具体工厂和产品族很方便,比如说,我们想要增加小米,只需要创建一个小米工厂XiaoMiFactory实现手机工厂接口PhoneFactory,合理的解决的简单工厂模式不能修改代码的缺点。但是,在现实使用中,简单工厂模式占绝大多数。
简单工厂模式与工厂方法模式比较:
结构的复杂度:简单工厂模式占优。
代码的复杂度:简单工厂模式占优。
编程的复杂度:简单工厂模式占优。
管理的复杂的:简单工厂模式占优。
因此,虽然简单工厂模式不符合设计模式,但是实际使用远大于工厂方法模式。
抽象工厂模式提供了一个创建一系列相关或者相互依赖对象的接口,无需指定它们具体的类(围绕一个超级工厂创建其他工厂,该超级工厂称为工厂的工厂)
主要角色:
//电脑接口
public interface Computer {
void play();
void watch();
}
//创建华为电脑对象
public class HuaWeiComputer implements Computer{
@Override
public void play() {
System.out.println("HuaWei's play!");
}
@Override
public void watch() {
System.out.println("HuaWei's watch!");
}
}
//手机接口
public interface Phone {
void send();
void call();
}
//创建华为手机对象
public class HuaWeiPhone implements Phone{
@Override
public void send() {
System.out.println("HuaWei's send");
}
@Override
public void call() {
System.out.println("HuaWei's call");
}
}
//抽象工厂
public interface IProductFactory {
//生产手机
Phone phone();
//生产电脑
Computer computer();
}
//创建华为工厂
public class HuaWeiFactory implements IProductFactory{
@Override
public Phone phone() {
return new HuaWeiPhone();
}
@Override
public Computer computer() {
return new HuaWeiComputer();
}
}
//测试类
public class Consumer {
public static void main(String[] args) {
HuaWeiFactory huaWeiFactory = new HuaWeiFactory();
Phone phone = huaWeiFactory.phone();
phone.call();
phone.send();
Computer computer = huaWeiFactory.computer();
computer.play();
computer.watch();
}
}
得到测试结果
HuaWei's call
HuaWei's send
HuaWei's play!
HuaWei's watch!
我们通过创建一个抽象工厂完成了对具体工厂的创建,只需要传入参数就可以实例化对象。具体产品在应用层的代码隔离,无需关心创建的细节将一个系列的产品统一到一起创建。将一系列产品规划到一起创建。但是,抽象工厂模式也存在着缺点。规定了所有可能被创建的产品集合,产品簇中扩展新的产品困难,不可以增加产品,只能增加品牌。