设计模式开坑

设计模式(一)–工厂和单例模式

其他笔记链接

JVM学习笔记(一)
JVM学习笔记(二)
JVM学习笔记(三)
JVM学习笔记(四)
(待更新…)

Java NIO
(待更新…)

设计模式(一)
设计模式(二)
设计模式(三)
设计模式(四)
(待更新…)

1. 23种设计模式

创建型模式

  • 工厂模式(Factory Pattern)
  • 抽象工厂模式(Abstract Factory Pattern)
  • 单例模式(Singleton Pattern)
  • 建造者模式(Builder Pattern)
  • 原型模式(Prototype Pattern)

结构型模式

  • 适配器模式(Adapter Pattern)
  • 桥接模式(Bridge Pattern)
  • 过滤器模式(Filter、Criteria Pattern)
  • 组合模式(Composite Pattern)
  • 装饰器模式(Decorator Pattern)
  • 外观模式(Facade Pattern)
  • 享元模式(Flyweight Pattern)
  • 代理模式(Proxy Pattern)

行为型模式

  • 责任链模式(Chain of Responsibility Pattern)
  • 命令模式(Command Pattern)
  • 解释器模式(Interpreter Pattern)
  • 迭代器模式(Iterator Pattern)
  • 中介者模式(Mediator Pattern)
  • 备忘录模式(Memento Pattern)
  • 观察者模式(Observer Pattern)
  • 状态模式(State Pattern)
  • 空对象模式(Null Object Pattern)
  • 策略模式(Strategy Pattern)
  • 模板模式(Template Pattern)
  • 访问者模式(Visitor Pattern)

2. OOP七大原则

  1. 开-闭原则(Open-Closed Principle, OCP)
  2. 里氏替换原则(Liskov Substitution Principle,LSP)
  3. 依赖倒置原则(Dependence Inversion Principle)
  4. 接口隔离原则(Interface Segregation Principle, ISP)
  5. 合成/聚合复用原则(Composite/Aggregate Reuse Principle,CARP)
  6. 迪米特法则(Law of Demeter LoD)
  7. 单一职责原则(Simple responsibility pinciple SRP)

3. 单例模式

特点

单例类只能有一个实例,单例类必须自己创建自己的唯一实例,单例类必须给所有其他对象提供这一实例。

关键实现

构造函数私有化(外界无法创建,只有在类内部才能创建)

对象实例私有化,对外只提供get方法获取这唯一实例。

六种实现方法

1.懒汉式一

初始化方式:懒加载(拿的时候才创建)

线程:不安全

public class singInstance{
    
    
    //不在类加载时创建
	private static singInstance instance;
    //构造函数私有化
    private singInstance(){
    
    }
    //get方法获取对象,并确保只创建一次
    public static singInstance getInstance(){
    
    
        if(instance == null){
    
    
            instance = new singInstance();
        }
        return instance;
    }
}

2.懒汉式二

初始化方式:懒加载(拿的时候才创建)

线程:安全

添加synchronized导致性能上的损失

public class singInstance{
    
    
    //不在类加载时创建
	private static singInstance instance;
    //构造函数私有化
    private singInstance(){
    
    }
    //添加synchronized确保多线程安全
    public static synchronized singInstance getInstance(){
    
    
        if(instance == null){
    
    
            instance = new singInstance();
        }
        return instance;
    }
}

3.饿汉式

初始化方式:非懒加载

线程:安全

在类加载时就创建的对象,确保线程安全,没有加synchronized性能上没有收影响。但是非懒加载,会堆积垃圾对象。

public class singInstance{
    
    
    //在类加载时创建
	private static singInstance instance = new singInstance();
    //构造函数私有化
    private singInstance(){
    
    }
    //直接放回已经创建好的对象
    public static singInstance getInstance(){
    
    
        return instance;
    }
}

4.双检锁/双重校验锁(DCL)

初始化方式:懒加载

线程:安全

public class singInstance{
    
    
    //使用volatile确保线程可见性
	private volatile static singInstance instance;
    //构造函数私有化
    private singInstance(){
    
    }
    //直接放回已经创建好的对象
    public static singInstance getInstance(){
    
    
        if(instance == null){
    
    
            //使用synchronized把类锁住,确保类对象使用的线程安全
            synchronized (singInstance.class){
    
    
                if(instance == null){
    
    
                    instance = new singInstance();
                }
            }
        }
    }
}

5.登记式(静态内部类)

初始化方式:懒加载

线程:安全

利用静态内部类需要显式调用才加载的机制,实现懒加载。因为 SingletonInter 类没有被主动使用,只有通过显式调用 getInstance 方法时,才会显式装载 SingletonInter 类,从而实例化 instance。

public class singInstance{
    
    
    //把对象放内部内里面
	private static class singInstanceInter(){
    
    
        private static final singInstance instance = new singInstance();  
    }
    
    //构造函数私有化
    private singInstance(){
    
    }
    //直接放回已经创建好的对象
    public static final singInstance getInstance(){
    
    
        return singInstanceInter.instance;
    }
}

6.枚举法

初始化方式:非懒加载

线程:安全

public enum Singleton {
    
      
    INSTANCE;  
    public void whateverMethod() {
    
      
    }  
}

4.工厂模式

静态工厂模式(简单工厂模式)

静态工厂模式,违背了开闭原则。想增加一个新的产品,就需要修改代码。

就像下面这张图片一样,product需要实现对应的产品接口,而工厂类负责对实现该Iproduc接口的实现类的创建,如果我们需要创建一台汽车只需通过工厂并告知其要建造哪种车即可。

为什么用工厂模式?

有人可能会想,为什么不直接NEW呢,要通过工厂创建。试想一下,假如某个产品的创建需要大量的初始化参数,那么我们只能new的话,需要手写大量参数,这是好的,而且在你的应用程序的类里面直接通过new出来的对象,那么new出来的对象就直接跟你的应用程序中的类有直接关联,那么你下系统耦合性就会很高。假如某一天上百个produce中某几个produce的构造参数改变了,你是否需要去你应用程序中的类修改你原有new的那行代码,这是很不好的。假如我们使用了工厂模式,我们只需去修改对应工厂类的代码即可,无需去你那一大堆应用程序中的类找那段new的代码。

在这里插入图片描述

代码实现

这次代码使用电脑做示范。

电脑产品接口

public Interface Computer {
    
    
    //电脑要会开机
    public void start();
}

联想电脑

public class HpComputer extends Computer{
    
    
    @Override
    public void start() {
    
    
        System.out.println("惠普电脑启动");
    }
}

华硕电脑

public class AsusComputer extends Computer {
    
    
    @Override
    public void start() {
    
    
        System.out.println("华硕电脑启动");
    }
}

英特尔电脑

public class InterComputer extends Computer {
    
    
    @Override
    public void start() {
    
    
        System.out.println("英特尔电脑启动");
    }
}

工厂

public class ComputerFactory {
    
    
    //只需告知工厂创建那种电脑即可
    public static Computer createComputer(String type){
    
    
        Computer mComputer=null;
        switch (type) {
    
    
            case "lenovo":
                mComputer=new LenovoComputer();
               break;
            case "Inter":
                mComputer=new InterComputer();
                break;
            case "asus":
                mComputer=new AsusComputer();
                break;

        }
        return mComputer;
    }
}

优缺点

  • 优点:避免了直接实例化类,降低了耦合性。
  • 缺点:违背了开放封闭原则,想增加一个新的产品,就需要修改代码。

工厂方法模式

工厂方法模式是在静态工厂上面做进一步的修改,原静态工厂模式只有单一的工厂,而工厂方法模式有多个工厂,每个产品都有其实现创建的工厂,这样增加一个新的产品时,我们只需要横向扩展工厂类即可达成目标,就无需去修改那唯一工厂的代码。弊端也挺明显的,没增加一个产品就需要创建其对应的工厂类,增加了系统的复杂度。

图片来自狂神说:

在这里插入图片描述

代码实现

产品接口

public Interface Car {
    
    
    public void drive();
}

工厂接口

public Interface CarFactory{
    
    
	//工厂要会建造汽车
	public Car createCar();
}

特斯拉车

public class Tesla implements Car{
    
    
	@Override
	public void drive(){
    
        
        System.out.println("特斯拉开车");
	}
}

特斯拉工厂

public class Tesla implements CarFactory{
    
    
	@Override
	public Car createCar(){
    
        
        return new Tesla();
	}
}

横向扩展

想横向扩展只需要添加对应的产品和其产品对应的工厂即可,虽然代码量变多了,但符合开闭原则。

优缺点

  • 缺点:增加系统的复杂度,没新建一个产品就需要新建一个对应的工厂。
  • 优点:扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 屏蔽产品的具体实现,调用者只关心产品的接口。

5. 抽象工厂模式

抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。

                                ┌────────┐
                             ─ >│ProductA│
┌────────┐    ┌─────────┐   │   └────────┘
│ Client │─ ─>│ Factory │─ ─
└────────┘    └─────────┘   │   ┌────────┐
                   ▲         ─ >│ProductB│
           ┌───────┴───────┐    └────────┘
           │               │
      ┌─────────┐     ┌─────────┐
      │Factory1 │     │Factory2 │
      └─────────┘     └─────────┘
           │   ┌─────────┐ │   ┌─────────┐
            ─ >│ProductA1│  ─ >│ProductA2│
           │   └─────────┘ │   └─────────┘
               ┌─────────┐     ┌─────────┐
           └ ─>│ProductB1│ └ ─>│ProductB2│
               └─────────┘     └─────────┘

代码实现

这次代码实现换成别的,有现实对入感一点。

手机产品接口

public Interface phone {
    
    
    public void open();
}

WIFI产品接口

public Interface wifi {
    
    
    public void openwifi();
}

抽象工厂接口

public Interface AbstractFactory {
	//工厂要回造手机
    public phone creatPhone();
    //会造wifi
    public wifi creatWifi();
}

小米工厂

public class MiniFactory {
    
    
	@Override
    public phone creatPhone(){
    
    
    	return new MiniPhone();
    }
    @Override
    public wifi creatWifi(){
    
    
    	return new Miniwifi();
    }
}

小米手机产品类

public class MiniPhone {
    
    
	@Override
    public void open(){
    
    
    	...
    }
}

小米WiFi产品类

public class Miniwifi {
    
    
	@Override
    public void openwifi(){
    
    
    	...
    }
}

华为手机工厂

public class HuaweiFactory {
	@Override
    public phone creatPhone(){
    	return new HuaweiPhone();
    }
    @Override
    public wifi creatWifi(){
    	return new Huaweiwifi();
    }
}

华为手机产品类

public class HuaweiPhone {
    
    
	@Override
    public void open(){
    
    
    	...
    }
}

华为WiFi产品类

public class Huaweiwifi {
    
    
	@Override
    public void openwifi(){
    
    
    	...
    }
}

优缺点

  • 优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
  • 缺点:还是违背了开闭原则,产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。

猜你喜欢

转载自blog.csdn.net/qq_43203949/article/details/115102748