图解Java设计模式

图解Java设计模式,第1张

Java的设计模式

文章目录
  • Java的设计模式
    • 1. 设计模式的七大原则
      • 1.1.单一职责原则
        • 1.1.1. 基本介绍
        • 1.1.2. 单一职责原则注意事项和细节
      • 1.2. 接口隔离原则
        • 1.2.2. 代码实现
      • 1.3. 依赖倒置原则
        • 1.3.2. 代码实现
      • 1.4. 里式替换原则
      • 1.5. 开闭原则
        • 1.5.1. 介绍
        • 1.5.2. 代码实现
      • 1.6. 迪米特原则
        • 1.6.1 介绍
        • 1.6.2. 代码
      • 1.7 合成复用原则
    • 2. 单例模式
      • 2.1 介绍
      • 2.2 懒汉式双重校验锁机制
      • 2.2. 饿汉式
      • 2.3. 单例模式注意事项和细节说明
    • 3. 工厂模式
    • 4. 原型模式
      • 4.1. 介绍
      • 4.2. 浅拷贝
      • 4.3. 深拷贝
      • 4.4.原型模式的注意事项和细节
    • 5.1. 建造者模式
      • 5.2. 代码实现
    • 6. 适配器模式
      • 6.1. 基本介绍
      • 6.2. 类适配器模式
      • 6.3. 对象适配器
      • 6.4. 接口适配器


1. 设计模式的七大原则 1.1.单一职责原则 1.1.1. 基本介绍

对类来说的,即一个类应该只负责一项职责。如类A负责两个不同职责:职责1,职责2。
当职责1需求变更而改变A时,可能造成职责2执行错误,所以需要将类A的粒度分解为
A1,A2

1.1.2. 单一职责原则注意事项和细节
  1. 降低类的复杂度,一个类只负责一项职责。
  2. 提高类的可读性,可维护性
  3. 降低变更引起的风险
  4. 通常情况下,我们应当遵守单一职责原则,只有逻辑足够简单,才可以在代码级违
    反单一职责原则;只有类中方法数量足够少,可以在方法级别保持单一职责原则
1.2. 接口隔离原则 1.2.2. 代码实现
package com.atguigu.principle.segregation.improve;

public class Segregation1 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// 使用一把
		A a = new A();
		a.depend1(new B()); // A类通过接口去依赖B类
		a.depend2(new B());
		a.depend3(new B());

		C c = new C();

		c.depend1(new D()); // C类通过接口去依赖(使用)D类
		c.depend4(new D());
		c.depend5(new D());

	}

}

// 接口1
interface Interface1 {
	void operation1();

}

// 接口2
interface Interface2 {
	void operation2();

	void operation3();
}

// 接口3
interface Interface3 {
	void operation4();

	void operation5();
}

class B implements Interface1, Interface2 {
	public void operation1() {
		System.out.println("B 实现了 operation1");
	}

	public void operation2() {
		System.out.println("B 实现了 operation2");
	}

	public void operation3() {
		System.out.println("B 实现了 operation3");
	}

}

class D implements Interface1, Interface3 {
	public void operation1() {
		System.out.println("D 实现了 operation1");
	}

	public void operation4() {
		System.out.println("D 实现了 operation4");
	}

	public void operation5() {
		System.out.println("D 实现了 operation5");
	}
}

class A { // A 类通过接口Interface1,Interface2 依赖(使用) B类,但是只会用到1,2,3方法
	public void depend1(Interface1 i) {
		i.operation1();
	}

	public void depend2(Interface2 i) {
		i.operation2();
	}

	public void depend3(Interface2 i) {
		i.operation3();
	}
}

class C { // C 类通过接口Interface1,Interface3 依赖(使用) D类,但是只会用到1,4,5方法
	public void depend1(Interface1 i) {
		i.operation1();
	}

	public void depend4(Interface3 i) {
		i.operation4();
	}

	public void depend5(Interface3 i) {
		i.operation5();
	}
}
1.3. 依赖倒置原则 1.3.2. 代码实现
package com.ckack.DesignPatterns.principle.inversion;

/**
 * @author: ckack
 * @date: 2022/4/17 13:40
 */

public class DependencyInversion {
    public static void main(String[] args) {
        //1. 构造方法
//        Person person = new Person(new Email());
        // 2. Setter 方法
        Person person = new Person();
        person.setI(new WeiXin());
        person.receive();
    }
}

interface IReceiver {
    String getInfo();
}

class Email implements IReceiver {

    @Override
    public String getInfo() {
        return "电子邮箱:Hello world";
    }
}

class WeiXin implements IReceiver {

    @Override
    public String getInfo() {
        return "WeiXin:Hello world";
    }
}

class Person {
    private IReceiver i;

    // 1. 构造方法
    public Person(IReceiver i) {
        this.i = i;
    }

    public Person() {
    }

    public void setI(IReceiver i) {
        this.i = i;
    }

    public void receive() {
        System.out.println(i.getInfo());
    }
}

1.4. 里式替换原则 1.5. 开闭原则 1.5.1. 介绍
  1. 开闭原则(Open Closed Principle)是编程中最基础、最重要的设计原则
  2. 一个软件实体如类,模块和函数应该对扩展开放(对提供方),对修改关闭(对使用
    方)。用抽象构建框架,用实现扩展细节。
  3. 当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已
    有的代码来实现变化。
  4. 编程中遵循其它原则,以及使用设计模式的目的就是遵循开闭原则
1.5.2. 代码实现
package com.atguigu.principle.ocp.improve;

public class Ocp {

	public static void main(String[] args) {
		//使用看看存在的问题
		GraphicEditor graphicEditor = new GraphicEditor();
		graphicEditor.drawShape(new Rectangle());
		graphicEditor.drawShape(new Circle());
		graphicEditor.drawShape(new Triangle());
		graphicEditor.drawShape(new OtherGraphic());
	}

}

//这是一个用于绘图的类 [使用方]
class GraphicEditor {
	//接收Shape对象,调用draw方法
	public void drawShape(Shape s) {
		s.draw();
	}

	
}

//Shape类,基类
abstract class Shape {
	int m_type;
	
	public abstract void draw();//抽象方法
}

class Rectangle extends Shape {
	Rectangle() {
		super.m_type = 1;
	}

	@Override
	public void draw() {
		// TODO Auto-generated method stub
		System.out.println(" 绘制矩形 ");
	}
}

class Circle extends Shape {
	Circle() {
		super.m_type = 2;
	}
	@Override
	public void draw() {
		// TODO Auto-generated method stub
		System.out.println(" 绘制圆形 ");
	}
}

//新增画三角形
class Triangle extends Shape {
	Triangle() {
		super.m_type = 3;
	}
	@Override
	public void draw() {
		// TODO Auto-generated method stub
		System.out.println(" 绘制三角形 ");
	}
}

//新增一个图形
class OtherGraphic extends Shape {
	OtherGraphic() {
		super.m_type = 4;
	}

	@Override
	public void draw() {
		// TODO Auto-generated method stub
		System.out.println(" 绘制其它图形 ");
	}
}

1.6. 迪米特原则 1.6.1 介绍
  1. 一个对象应该对其他对象保持最少的了解
  2. 类与类关系越密切,耦合度越大
  3. 迪米特法则(Demeter Principle)又叫最少知道原则,即一个类对自己依赖的类知道的
    越少越好。也就是说,对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内
    部。对外除了提供的public 方法,不对外泄露任何信息
  4. 迪米特法则还有个更简单的定义:只与直接的朋友通信
  5. 直接的朋友:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,
    我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖,关联,组合,聚合
    等。其中,我们称出现成员变量,方法参数,方法返回值中的类为直接的朋友,而
    出现在局部变量中的类不是直接的朋友。也就是说,陌生的类最好不要以局部变量
    的形式出现在类的内部。
1.6.2. 代码
package com.atguigu.principle.demeter.improve;

import java.util.ArrayList;
import java.util.List;

//客户端
public class Demeter1 {

	public static void main(String[] args) {
		System.out.println("~~~使用迪米特法则的改进~~~");
		//创建了一个 SchoolManager 对象
		SchoolManager schoolManager = new SchoolManager();
		//输出学院的员工id 和  学校总部的员工信息
		schoolManager.printAllEmployee(new CollegeManager());

	}

}


//学校总部员工类
class Employee {
	private String id;

	public void setId(String id) {
		this.id = id;
	}

	public String getId() {
		return id;
	}
}


//学院的员工类
class CollegeEmployee {
	private String id;

	public void setId(String id) {
		this.id = id;
	}

	public String getId() {
		return id;
	}
}


//管理学院员工的管理类
class CollegeManager {
	//返回学院的所有员工
	public List<CollegeEmployee> getAllEmployee() {
		List<CollegeEmployee> list = new ArrayList<CollegeEmployee>();
		for (int i = 0; i < 10; i++) { //这里我们增加了10个员工到 list
			CollegeEmployee emp = new CollegeEmployee();
			emp.setId("学院员工id= " + i);
			list.add(emp);
		}
		return list;
	}
	
	//输出学院员工的信息
	public void printEmployee() {
		//获取到学院员工
		List<CollegeEmployee> list1 = getAllEmployee();
		System.out.println("------------学院员工------------");
		for (CollegeEmployee e : list1) {
			System.out.println(e.getId());
		}
	}
}

//学校管理类

//分析 SchoolManager 类的直接朋友类有哪些 Employee、CollegeManager
//CollegeEmployee 不是 直接朋友 而是一个陌生类,这样违背了 迪米特法则 
class SchoolManager {
	//返回学校总部的员工
	public List<Employee> getAllEmployee() {
		List<Employee> list = new ArrayList<Employee>();
		
		for (int i = 0; i < 5; i++) { //这里我们增加了5个员工到 list
			Employee emp = new Employee();
			emp.setId("学校总部员工id= " + i);
			list.add(emp);
		}
		return list;
	}

	//该方法完成输出学校总部和学院员工信息(id)
	void printAllEmployee(CollegeManager sub) {
		
		//分析问题
		//1. 将输出学院的员工方法,封装到CollegeManager
		sub.printEmployee();
	
		//获取到学校总部员工
		List<Employee> list2 = this.getAllEmployee();
		System.out.println("------------学校总部员工------------");
		for (Employee e : list2) {
			System.out.println(e.getId());
		}
	}
}

1.7 合成复用原则

2. 单例模式
参考:https://blog.csdn.net/m0_57310550/article/details/123500229?spm=1001.2014.3001.5502
2.1 介绍
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。
2.2 懒汉式双重校验锁机制
package com.ckack.DesignPatterns.simple.type3;

/**
 *懒汉式双重校验锁机制
 * @author: ckack
 * @date: 2022/4/19 21:41
 */

public class SingletonTest03 {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        System.out.println(instance1 == instance);
        System.out.println(instance1.hashCode());
        System.out.println(instance.hashCode());
    }
}


class Singleton {
    private static volatile Singleton instance;

    private Singleton() {

    }
    // 当使用该方法是 才去创建

    /**
     * 懒汉式  加入synchronized 同步处理代码 解决线程安全问题
     */
    public static Singleton getInstance() {

        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();

                }
            }
        }
        return instance;
    }
}

2.2. 饿汉式
package com.ckack.DesignPatterns.simple.type1;

/**
 * @author: ckack
 * @date: 2022/4/19 21:22
 */

public class SingletonTest01 {
    public static void main(String[] args) {
        Singleton instance = Singleton.getInstance();
        Singleton instance1 = Singleton.getInstance();
        System.out.println(instance1 == instance);
        System.out.println(instance1.hashCode());
        System.out.println(instance.hashCode());
    }
}

/**
 * 方法1
 * 饿汉式(静态变量)
 * 缺点:在类装载的时候就完成实例化,没有达到懒加载效果 如果都没用的话 会造成 内存浪费
 * */
class Singleton {
    private Singleton() {

    }
    private final static Singleton instance = new Singleton();

    //对外提供一个公有的静态方法
    public static Singleton getInstance() {
        return instance;
    }
}
/**
 * 方法二
 * 内部类
 * @author: ckack
 * @date: 2022/4/20 21:53
 */

public class Singleton2 {

    private static class SingletonInstance {
        private static final Singleton2 INSTANCE = new Singleton();
    }

    public static Singleton2 getInstance() {
        return SingletonInstance.INSTANCE;
    }
}
2.3. 单例模式注意事项和细节说明
1) 单例模式保证了 系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,
   使用单例模式可以提高系统性能
2) 当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new
3) 单例模式使用的场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级对象),
   但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂等)
3. 工厂模式 4. 原型模式 4.1. 介绍
1) 原型模式(Prototype模式)是指:用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象
2) 原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节
3) 工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建,即 对象.clone()
4.2. 浅拷贝
通过实现Clone接口
package com.ckack.DesignPatterns.prototype;

/**
 * @author: ckack
 * @date: 2022/4/21 20:35
 */

public class Sheep implements Cloneable {
    private String name;
    private String age;
    private String color;

    public Sheep friend;
    public Sheep() {
    }

    public Sheep(String name, String age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                ", color='" + color + '\'' +
                ", friend=" + friend +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Sheep sheep = (Sheep) super.clone();
        return sheep;
    }

}

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        Sheep sheep = new Sheep("aaa", "111", "222");
        sheep.friend = new Sheep("friend", "22", "222");
        Sheep sheep2 = (Sheep) sheep.clone();
        System.out.println(sheep2.friend.hashCode());
        System.out.println(sheep.friend.hashCode());
    }
}

4.3. 深拷贝
package com.ckack.DesignPatterns.prototype.deepclone;

import java.io.Serializable;

/**
 * @author: ckack
 * @date: 2022/4/21 20:52
 */

public class DeepCloneableTarget implements Cloneable, Serializable {
    private static final long sericaVersionUID = 1L;
    private String cloneName;
    private String cloneClass;

    public DeepCloneableTarget(String cloneName, String cloneClass) {
        this.cloneName = cloneName;
        this.cloneClass = cloneClass;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

//##############################################################
package com.ckack.DesignPatterns.prototype.deepclone;

import java.io.*;

/**
 * @author: ckack
 * @date: 2022/4/21 20:56
 */

public class DeepProtoType implements Cloneable, Serializable {
    public String name;
    public DeepCloneableTarget deepCloneableTarget;

    //1. 使用clone的方法
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object deep = null;
        //完成对基本数据类型的克隆
        deep = super.clone();

        //对引用类型的属性进行单独处理
        DeepProtoType deepProtoType = (DeepProtoType) deep;
        deepProtoType.deepCloneableTarget = (DeepCloneableTarget) deepCloneableTarget.clone();
        return deep;
    }

    //2. 通过对象的序列化 实习深拷贝
    public Object deepClone() throws IOException {
        //创建流对象
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;

        try {

            //序列化 *** 作
            bos = new ByteArrayOutputStream();
            //字节输出流 换成对象输出流
            oos = new ObjectOutputStream(bos);
            // 当前这个对象以对象流的方式输出
            oos.writeObject(this);
            //反序列化
            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            DeepProtoType deepProtoType = (DeepProtoType) ois.readObject();
            return deepProtoType;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            bos.close();
            oos.close();
            bis.close();
            ois.close();
        }
    }
}
//######################################################################

import java.io.IOException;

/**
 * @author: ckack
 * @date: 2022/4/21 21:08
 */

public class Client {
    public static void main(String[] args) throws IOException {
        DeepProtoType deepProtoType = new DeepProtoType();
        deepProtoType.deepCloneableTarget = new DeepCloneableTarget("11", "22");
        deepProtoType.name = "231";

        DeepProtoType o = (DeepProtoType) deepProtoType.deepClone();
        System.out.println(deepProtoType.deepCloneableTarget.hashCode());
        System.out.println(o.deepCloneableTarget.hashCode());
    }
}

4.4.原型模式的注意事项和细节
1) 创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率
2) 不用重新初始化对象,而是动态地获得对象运行时的状态
3) 如果原始对象发生变化(增加或者减少属性),其它克隆对象的也会发生相应的变化,无需修改代码
4) 在实现深克隆的时候可能需要比较复杂的代码
5) 缺点:需要为每一个类配备一个克隆方法,这对全新的类来说不是很难,但对已有的类进行改造时,需要修改其源代码,违背了ocp原则.
5.1. 建造者模式 5.2. 代码实现
public class House {
	private String baise;
	private String wall;
	private String roofed;
	public String getBaise() {
		return baise;
	}
	public void setBaise(String baise) {
		this.baise = baise;
	}
	public String getWall() {
		return wall;
	}
	public void setWall(String wall) {
		this.wall = wall;
	}
	public String getRoofed() {
		return roofed;
	}
	public void setRoofed(String roofed) {
		this.roofed = roofed;
	}
	
}

public class CommonHouse extends HouseBuilder {

    @Override
    public void buildBasic() {
        System.out.println("普通房子打地基5米");
    }

    @Override
    public void buildWalls() {
        System.out.println("普通房子砌墙10cm ");
    }
    @Override
    public void roofed() {
        System.out.println("普通房子屋顶");
    }
}

package com.ckack.DesignPatterns.construction;

public class HighBuilding extends HouseBuilder {

	@Override
	public void buildBasic() {
		System.out.println("高楼的打地基100米");
	}
	@Override
	public void buildWalls() {
		System.out.println("高楼的砌墙20cm");
	}
	@Override
	public void roofed() {
		// TODO Auto-generated method stub
		System.out.println("高楼的透明屋顶");
	}
}

package com.ckack.DesignPatterns.construction;


// 抽象的建造者
public abstract class HouseBuilder {

    protected House house = new House();

    //将建造的流程写好, 抽象的方法
    public abstract void buildBasic();

    public abstract void buildWalls();

    public abstract void roofed();

    //建造房子好, 将产品(房子) 返回
    public House buildHouse() {
        return house;
    }

}

public class HouseDirector {
	HouseBuilder houseBuilder = null;	
	public HouseDirector(HouseBuilder houseBuilder) {
		this.houseBuilder = houseBuilder;
	}
	public void setHouseBuilder(HouseBuilder houseBuilder) {
		this.houseBuilder = houseBuilder;
	}
	public House constructHouse() {
		houseBuilder.buildBasic();
		houseBuilder.buildWalls();
		houseBuilder.roofed();
		return houseBuilder.buildHouse();
	}
}

public class Client {
    public static void main(String[] args) {
        CommonHouse commonHouse = new CommonHouse();
        HouseDirector houseDirector = new HouseDirector(commonHouse);    
        House house = houseDirector.constructHouse();
        System.out.println("--------------------------");
        HighBuilding highBuilding = new HighBuilding();
        houseDirector.setHouseBuilder(highBuilding);
        houseDirector.constructHouse();
    }
}

6. 适配器模式 6.1. 基本介绍
1) 适配器模式(Adapter Pattern)将某个类的接口转换成客户端期望的另一个接口表示,主的目的是兼容性,让原本因接口不匹配不能一起工作的两个类可以协同工作。其别名为包装器(Wrapper)
2) 适配器模式属于结构型模式
3) 主要分为三类:类适配器模式、对象适配器模式、接口适配器模式
6.2. 类适配器模式
//源
public abstract class Voltage220 {
    int output220() {
        int src = 220;
        System.out.println(String.format("电压:%s", src));
        return src;
    }
}

//
//输出
public interface Voltage5V {
    int output5V();
}

//适配器 实现接口
public class ClassAdapter extends Voltage220 implements Voltage5V{

    @Override
    public int output5V() {
        int src = output220();
        src = src / 44;
        return src;
    }
}


public class phone {
    public void Charing(Voltage5V v) {
        int i = v.output5V();
        System.out.println(i);
    }
}

public class client {
    public static void main(String[] args) {
        phone phone = new phone();
        phone.Charing(new ClassAdapter());
    }
}

6.3. 对象适配器
public  class Voltage220 {
    int output220() {
        int src = 220;
        System.out.println(String.format("电压:%s", src));
        return src;
    }
}



public interface Voltage5V {
    int output5V();
}


public class ClassAdapter implements Voltage5V {

    private Voltage220 voltage220;

    public void setVoltage220(Voltage220 voltage220) {
        this.voltage220 = voltage220;
    }

    @Override
    public int output5V() {
        int src = this.voltage220.output220();
        src = src / 44;
        return src;
    }
}

public class phone {
    public void Charing(Voltage5V v) {
        int i = v.output5V();
        System.out.println(i);
    }
}

public class client {
    public static void main(String[] args) {
        phone phone = new phone();
        ClassAdapter classAdapter = new ClassAdapter();
        classAdapter.setVoltage220(new Voltage220());
        phone.Charing(classAdapter);
    }
}
6.4. 接口适配器
public interface interface1 {
    void mi();

    void m2();

    void m3();

    void m4();
}

public abstract class AbsAdapter implements interface1{

    @Override
    public void mi() {
        System.out.println("father.mi");
    }

    @Override
    public void m2() {

    }

    @Override
    public void m3() {

    }

    @Override
    public void m4() {

    }
}

public class interfaceadapter extends AbsAdapter {
    @Override
    public void mi() {
        System.out.println("m1");
    }
}


public class client {
    public static void main(String[] args) {
        interfaceadapter interfaceadapter = new interfaceadapter();
        interfaceadapter.mi();
        AbsAdapter absAdapter = new AbsAdapter(){
            @Override
            public void mi(){
                System.out.println("son");
            }
        };
        absAdapter.mi();
    }
}


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/720535.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-25
下一篇 2022-04-25

发表评论

登录后才能评论

评论列表(0条)

保存