设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。
设计模式不是一种方法和技术,而是一种思想。
设计模式和具体的语言无关,学习设计模式就是要建立面向对象的思想,尽可能的面向接口编程,低耦合,高内聚,使设计的程序可复用。
学习设计模式能够促进对面向对象思想的理解,反之亦然。它们相辅相成
简单一句话:设计模式就是经验的总结
设计模式的几个要素
设计模式的分类
创建型模式:简单工厂模式,工厂方法模式,抽象工厂模式,建造者模式,原型模式,单例模式。(6个)
结构型模式:外观模式、适配器模式、代理模式、装饰模式、桥接模式、组合模式、享元模式。(7个)
行为型模式:模版方法模式、观察者模式、状态模式、职责链模式、命令模式、访问者模式、策略模式、备忘录模式、迭代器模式、解释器模式。(10个)
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
1、单例类只能有一个实例。也就是只有一个对象
2、单例类必须自己创建自己的唯一实例。 写单例构造方法是要私有的
3、单例类必须给所有其他对象提供这一实例。 在该方法中,提供一个方法,用于获取该对象
私有构造方法
在本类的成员位置,创建出自己类对象
提供公共方法,返回创建的对象 ,该方法必须是静态的
package com.suyv.singleton;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 10:46
* @Description: 饿汉式单例模式
*/
public class A {
// 2.定义变量接收类的对象
private static A a = new A();
// 1.私有化构造器
private A(){
}
// 3.定义静态方法返回类的对象
public static A getInstance(){
return a;
}
}
测试
package com.suyv.singleton;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 10:49
* @Description: 饿汉式单例模式测试
*/
public class ADemo01 {
public static void main(String[] args) {
A a1 = A.getInstance();
A a2 = A.getInstance();
System.out.println(a1); // com.suyv.singleton.A@677327b6
System.out.println(a2); // com.suyv.singleton.A@677327b6
System.out.println(a1 == a2); // true
}
}
package com.suyv.singleton;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 10:52
* @Description: 懒汉式单例模式
*/
public class B {
// 2.定义静态变量接收创建的对象
private static B b;
// 1.私有化构造器
private B(){
}
// 3.定义一个静态方法,第一次创建时才创建对象,后面调用都会返回这一个对象
public static B getInstance(){
if (b == null){
b = new B();
}
return b;
}
}
测试
package com.suyv.singleton;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 10:56
* @Description: 懒汉式单例模式测试
*/
public class BDemo01 {
public static void main(String[] args) {
B b1 = B.getInstance();
B b2 = B.getInstance();
System.out.println(b1); // com.suyv.singleton.B@677327b6
System.out.println(b2); // com.suyv.singleton.B@677327b6
System.out.println(b1 == b2); // true
}
}
饿汉式:在类初始化时就直接创建单例对象,而类初始化过程是没有线程安全问题的
问题出现:
package com.suyv.singleton;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 10:52
* @Description: 懒汉式单例模式
*/
public class B{
// 2.定义静态变量接收创建的对象
private static volatile B b;
// 1.私有化构造器
private B(){
}
// 3.定义一个静态方法,第一次创建时才创建对象,后面调用都会返回这一个对象
public static B getInstance(){
if (b == null){
try {
// 让问题暴露更加明显
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
b = new B();
}
return b;
}
}
package com.suyv.singleton;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 10:56
* @Description: 懒汉式单例模式线程安全测试
*/
public class BDemo02 {
static B b1 = null;
static B b2 = null;
public static void main(String[] args) {
Thread t1 = new Thread(){
@Override
public void run() {
b1 = B.getInstance();
}
};
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
b2 = B.getInstance();
}
});
t1.start();
t2.start();
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(b1); // com.suyv.singleton.B@677327b6
System.out.println(b2); // com.suyv.singleton.B@14ae5a5
System.out.println(b1 == b2); // false
}
}
解决方案:
package com.suyv.singleton;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 10:52
* @Description: 懒汉式单例模式
*/
public class B{
// 2.定义静态变量接收创建的对象
private static volatile B b;
// 1.私有化构造器
private B(){
}
// 3.定义一个静态方法,第一次创建时才创建对象,后面调用都会返回这一个对象
/*public static B getInstance(){
if (b == null){
try {
// 让问题暴露更加明显
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
b = new B();
}
return b;
}*/
// 使用双重判断,效率更高
public static B getInstance(){
if (b == null){
synchronized (B.class){
if (b == null){
b = new B();
}
}
}
return b;
}
}
package com.suyv.singleton;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 10:56
* @Description: 懒汉式单例模式线程安全测试
*/
public class BDemo03 {
static B b1 = null;
static B b2 = null;
public static void main(String[] args) {
Thread t1 = new Thread(){
@Override
public void run() {
b1 = B.getInstance();
}
};
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
b2 = B.getInstance();
}
});
t1.start();
t2.start();
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(b1); // com.suyv.singleton.B@677327b6
System.out.println(b2); // com.suyv.singleton.B@677327b6
System.out.println(b1 == b2); // true
}
}
解决程线安全问题
双层if判断的原因
单例模式的应用场景和好处
Runtime
任务管理器对象、获取运行时对象
使用单例模式,可以避免资源浪费。
工厂设计模式,属于创建型,用于对象的创建; 简单来说,就是专门生产对象的
package com.suyv.factory;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 11:26
* @Description: 动物抽象类
*/
public abstract class Animal {
public abstract void eat();
}
package com.suyv.factory;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 11:27
* @Description: 猫类
*/
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
package com.suyv.factory;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 11:28
* @Description: 狗类
*/
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃骨头");
}
}
package com.suyv.factory;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 11:29
* @Description: 工厂设计类,这个类就是专门来生产对象,今后从这个工厂类中可以直接获取类对象
*/
public class AnimalFactory {
private AnimalFactory(){}
public static Dog createDog(){
return new Dog();
}
public static Cat creatCat(){
return new Cat();
}
}
package com.suyv.factory;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 11:32
* @Description: 工厂模式测试
*/
public class AnimalTest {
public static void main(String[] args) {
// 工厂设计模式:
// 优点:我可以直接通过工厂来获取对象
// 缺点:如果要加对象,需要修改工厂类,不便于后期的维护
// 使用工厂模式创建对象
Cat cat = AnimalFactory.creatCat();
Dog dog = AnimalFactory.createDog();
// 调用方法
cat.eat();
dog.eat();
}
}
package com.suyv.factory1;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 12:11
* @Description: 创建一个接口
*/
public interface Product {
public void doSomething();
}
package com.suyv.factory1;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 12:12
* @Description: 实现接口的实现类
*/
public class ConcreteProduct implements Product{
@Override
public void doSomething() {
System.out.println("Doing something in ConcreteProduct");
}
}
package com.suyv.factory1;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 12:14
* @Description: 实例工厂类
*/
public class ProductFactory {
public Product createProduct(){
return new ConcreteProduct();
}
}
package com.suyv.factory1;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 12:15
* @Description: 实例工厂测试类
*/
public class ProductTest {
public static void main(String[] args) {
ProductFactory factory = new ProductFactory();
Product product = factory.createProduct();
product.doSomething();
}
}
package com.suyv.staticfactory;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 12:21
* @Description: 定义一个咖啡类
*/
public abstract class Coffee {
public abstract String getName();
//加糖
public void addsugar() {
System.out.println("加糖");
}
//加奶
public void addMilk() {
System.out.println("加奶");
}
}
package com.suyv.staticfactory;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 12:22
* @Description: 美式咖啡
*/
public class AmericanCoffee extends Coffee{
@Override
public String getName() {
return "美式咖啡";
}
}
package com.suyv.staticfactory;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 12:23
* @Description: 拿铁咖啡
*/
public class LatteCoffee extends Coffee{
@Override
public String getName() {
return "拿铁咖啡";
}
}
package com.suyv.staticfactory;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 12:29
* @Description: 咖啡工厂类--静态工厂
*/
public class SimpleCoffeeFactory {
public static Coffee createCoffee(String type) {
//声明Coffee类型的变量,根据不同类型创建不同的coffee子类对象
Coffee coffee = null;
if("american".equals(type)) {
coffee = new AmericanCoffee();
} else if("latte".equals(type)) {
coffee = new LatteCoffee();
} else {
throw new RuntimeException("对不起,您所点的咖啡没有");
}
return coffee;
}
}
package com.suyv.staticfactory;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 12:24
* @Description: 咖啡店类
*/
public class CoffeeStore {
public Coffee orderCoffee(String type) {
Coffee coffee = SimpleCoffeeFactory.createCoffee(type);
//加配料
coffee.addMilk();
coffee.addsugar();
return coffee;
}
}
package com.suyv.staticfactory;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 12:26
* @Description: 静态工厂类测试
*/
public class CofferTest {
public static void main(String[] args) {
//创建咖啡店类对象
CoffeeStore store = new CoffeeStore();
Coffee coffee = store.orderCoffee("latte");
System.out.println(coffee.getName());
}
}
模版方法模式,简称为模板设计模式,它主要思想是:把通用的代码生成一个模板,可以反复的使用
package com.suyv.template;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 14:00
* @Description: 创建一个模板类
*/
public abstract class GetTime {
/**
* @description: 获取一段程序的运行时间
* @author: 憨憨浩浩
* @date: 2023/12/27 14:02
* @param: []
* @return: long
**/
public long getTime(){
long start = System.currentTimeMillis();
// 程序
code();
long end = System.currentTimeMillis();
return end - start;
}
public abstract void code();
}
package com.suyv.template;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 14:03
* @Description: 用户使用模板类
*/
public class ForDemo extends GetTime{
@Override
public void code() {
for (int i = 0; i < 100; i++) {
System.out.println(i);
}
}
}
package com.suyv.template;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 14:04
* @Description: 模板设计模式测试类
*/
public class TemplateTest {
public static void main(String[] args) {
ForDemo forDemo = new ForDemo();
System.out.println(forDemo.getTime() + "毫秒");
}
}
装饰设计模式: 增强原有对象的功能
原本有一个对象,但是这个对象的功能不够强,采用装饰设计模式,对原对象中功能进行增强
回想一下我们当时讲的缓冲流,其实就是装饰设计模式
package com.suyv.decorate;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 14:09
* @Description: TODO
*/
public class Phone {
public void call(){
System.out.println("手机打电话功能!");
}
}
package com.suyv.decorate;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 14:10
* @Description: TODO
*/
public class SendMsg {
private Phone phone;
public SendMsg(Phone phone) {
this.phone = phone;
}
//增强原有手机的功能
public void msg(){
System.out.println("发彩信");
System.out.println("发短信");
phone.call();
}
}
package com.suyv.decorate;
/**
* @Author: 憨憨浩浩
* @CreateTime: 2023-12-27 14:11
* @Description: TODO
*/
public class PhoneTest {
public static void main(String[] args) {
SendMsg sendMsg = new SendMsg(new Phone());
sendMsg.msg();
}
}
面向对象思想设计原则
在实际的开发中,我们要想更深入的了解面向对象思想,就必须熟悉前人总结过的面向对象的思想的设计原则
其实就是开发人员经常说的"高内聚,低耦合”
也就是说,每个类应该只有一个职责,对外只能提供一种功能,而引起类变化的原因应该只有一个。在设计模式中,所有的设计模式都遵循这一原则。能自己完成的事就不要麻烦别人,把一件事细化细化,只做一件事情
能自己完成的事就不要麻烦别人,把一件事细化细化,只做一件事情
核心思想是:一个对象对扩展开放,对修改关闭。
其实开闭原则的意思就是:对类的改动是通过增加代码进行的,而不是修改现有代码。
也就是说软件开发人员一旦写出了可以运行的代码,就不应该去改动它,而是要保证它能一直运行下去,如何能够做到这一点呢?这就需要借助于抽象和多态,即把可能变化的内容抽象出来,从而使抽象的部分是相对稳定的,而具体的实现则是可以改变和扩展的
核心思想:在任何父类出现的地方都可以用它的子类来替代。
其实就是说:同一个继承体系中的对象应该有共同的行为特征。
核心思想:要依赖于抽象,不要依赖于具体实现。
其实就是说:在应用程序中,所有的类如果使用或依赖于其他的类,则应该依赖这些其他类的抽象类,而不是这些其他类的具体类。为了实现这一原则,就要求我们在编程的时候针对抽象类或者接口编程,而不是针对具体实现编程。
核心思想:不应该强迫程序依赖它们不需要使用的方法。
其实就是说:一个接口不需要提供太多的行为,一个接口应该只提供一种对外的功能,不应该把所有的操作都封装到一个接口中。
核心思想:一个对象应当对其他对象尽可能少的了解
其实就是说:降低各个对象之间的耦合,提高系统的可维护性。在模块之间应该只通过接口编程,而不理会模块的内部工作原理,它可以使各个模块耦合度降到最低,促进软件的复用