文章目录
1. 为什么要使用设计模式?
- 代码重用性 (相同功能的代码,不用多次编写)
- 可读性 (编程规范性, 便于其他程序员的阅读和理解)
- 可扩展性 (当需要增加新的功能时,非常的方便,称为可维护)
- 可靠性 (当我们增加新的功能后,对原来的功能没有影响)
- 使程序呈现高内聚,低耦合的特性
2. 设计模式七大原则
- 单一职责原则SRP(Single Responsibility Principle):一个类或者一个方法应该只负责一项职责
- 接口隔离原则ISP(the Interface Segregation Principle ISP):客户端不应该依赖它不需要的接口(接口有A、B方法,只用到A的话,把接口拆成两个)
- 依赖倒转(倒置)原则DIP(the Dependency Inversion Principle DIP):面向接口编程,私有属性依赖接口或抽象类,继承时遵循里氏替换原则
- 里氏替换原则(the Liskov Substitution Principle LSP):继承时,子类的尽量不要重写父类方法,父类的通用方法尽量不要改,避免发生未知错误,可用聚合、组合、依赖解决
- 开闭原则ocp(Open-Close Principle):模块和函数应该对扩展开放(对提供方),对修改关闭(对使用方)。(通过增加代码而不是修改代码完成)用抽象构建框架,用实现扩展细节
- 迪米特法则:一个对象尽量降低对其他类的依赖,无关的类不要以局部变量出现在类的内部
- 合成复用原则:使用合成/聚合的方式,而不是使用继承;依赖:方法传参传给他 聚合:声明属性和set的方法,组合 直接属性new一个
3. 设计模式及其类型(23种)
3.1. 创建型模式
3.1.1. 单例模式
- 单例模式:保证在系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)
- 使用场景:频繁的创建和销毁的对象、创建对象时耗时过多或耗费资源过多(重量级对象),但又常用的工具类对象、频繁访问数据库或文件的对象(数据库连接池、多线程池、SessionFactory等)
- 步骤:1. 构造器私有化, 外部不能new 2.本类内部创建对象实例 3. 提供一个公有的静态方法,返回实例对象
//饿汉式:线程安全、无延时加载、内存浪费(在类装载的时候就完成实例,避免了多线程的同步问题)
class Singleton {
private Singleton() {}
private final static Singleton instance = new Singleton();
public static Singleton getInstance() { return instance; }
}
//懒汉式:线程安全,同步方法,但效率太低
class Singleton {
private Singleton() {}
private static Singleton instance;
public static synchronized Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
//双重检查:线程安全;延迟加载;效率较高√
class Singleton {
private Singleton() {}
private static volatile Singleton instance;//将线程中的东西更新到主存
//需要加volatile关键字,否则会出现错误,因为JVM指令的重排优化
//创建对象包括三个指令
// 1.new #2 <T> :分配内存地址,属性初始化并赋予默认值
// 2.invokespecial #3 <T.<init>> 调用构造方法并完成对象初始化
// 3.astore_1 将对象指针指向对象 如果以上三个指令顺序错误,将导致程序出错
public static Singleton getInstance() {
if(instance == null) {
synchronized (Singleton.class) {
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
//静态内部类:延时加载,效率高;类的静态属性只会在第一次加载类的时候初始化,在类进行初始化时,别的线程是无法进入的。保证了线程的安全性√
class Singleton {
private Singleton() {}
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton(); //写一个静态内部类,该类中有一个静态属性 Singleton
}
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
//枚举:枚举线程安全,而且还能防止反序列化重新创建新的对象。
public class Cilent {
public static void main(String[] args) {
Singleton instance = Singleton.INSTANCE;
instance.sayOK();
}
}
enum Singleton {
INSTANCE;
public void sayOK() { System.out.println("ok~"); }
}
3.1.2. 工厂模式
- 工厂模式:大量的创建某种、某类或者某批对象,定义创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类。
class Client{
public static void main(String[] args) {
new ProductFactoryB().useProduct("ProductC");
}
}
interface Product{void createProduct();}
class ProductA implements Product{public void createProduct(){System.out.println("ProductA");}}
class ProductB implements Product{public void createProduct(){System.out.println("ProductB");}}
class ProductC implements Product{public void createProduct(){System.out.println("ProductC");}}
class ProductD implements Product{public void createProduct(){System.out.println("ProductD");}}
//抽象工厂:描述具体工厂的公共接口 核心,只需传入名字
abstract class ProductFactory {
private Product product = null;
void useProduct(String name){product = getProduct(name);product.createProduct();}
abstract Product getProduct(String name);
}
//具体工厂:描述具体工厂,创建产品的实例,供外界调用
class ProductFactoryA extends ProductFactory{
public Product getProduct(String name){
if(name.equals("ProductA")){ return new ProductA(); }else{ return new ProductB(); }
}
}
class ProductFactoryB extends ProductFactory{
public Product getProduct(String name){
if(name.equals("ProductC")){ return new ProductC(); }else{ return new ProductD(); }
}
}
3.1.3. 抽象工厂模式
- 抽象工厂模式:定义了一个interface用于创建相关或有依赖关系的对象簇,而无需指明具体的类
- 将工厂抽象成两层,AbsFactory(抽象工厂) 和 具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展
class Client{
public static void main(String[] args) {
new FoodFactory(new ProductFactoryB()).getProduct("ProductC");
}
}
interface Product{void createProduct();}
class ProductA implements Product{public void createProduct(){System.out.println("ProductA");}}
class ProductB implements Product{public void createProduct(){System.out.println("ProductB");}}
class ProductC implements Product{public void createProduct(){System.out.println("ProductC");}}
class ProductD implements Product{public void createProduct(){System.out.println("ProductD");}}
//抽象工厂:描述具体工厂的公共接口
interface AbsProductFactory {public Product getProduct(String name);}
//具体工厂:描述具体工厂,创建产品的实例,供外界调用
class ProductFactoryA implements AbsProductFactory{
public Product getProduct(String name){
if(name.equals("ProductA")){ return new ProductA(); }else{ return new ProductB(); }
}
}
class ProductFactoryB implements AbsProductFactory{
public Product getProduct(String name){
if(name.equals("ProductC")){ return new ProductC(); }else{ return new ProductD(); }
}
}
//抽象产品族:描述抽象产品的公共接口 核心。传入工厂和名字 增加了这个类可以指定工厂生产
class FoodFactory {
AbsProductFactory factory;
public FoodFactory(AbsProductFactory factory) {
this.factory = factory;
}
public void getProduct(String name) {
this.factory.getProduct(name).createProduct();
}
}
3.1.4. 原型模式
- 原型模式(Prototype模式):拷贝对象实例(不是同一个对象)违背了ocp原则;逃避构造函数的约束
- 资源优化场景:类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
- 性能和安全要求的场景:通过new产生一个对象需要非常繁琐的数据准备或访问权限时
- 一个对象多个修改者的场景:一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以使用原型模式拷贝多个对象供调用者使用
- 创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率
//浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象(基本数据类型直接复制,引用数据类型引用传递)
//1.实现Cloneable接口,2.重写clone()方法:
public class Client {
public static void main(String[] args) {
Sheep sheep = new Sheep("tom");
Sheep firend = new Sheep("jack");
sheep.setFriend(firend);
Sheep sheep2 = (Sheep)sheep.clone(); //克隆
System.out.println("firend=" + firend + ",sheep2.friend=" + sheep2.getFriend());
}
}
class Sheep implements Cloneable {
private String name;//基本数据类型直接复制
private Sheep friend; //引用数据类型引用传递
public Sheep(String name) {this.name = name;}
public String getName() { return name; }
public Sheep getFriend() { return friend; }
public void setFriend(Sheep friend) { this.friend = friend; }
@Override
protected Object clone() {//克隆该实例,使用默认的clone方法来完成
Sheep sheep = null;
try {
sheep = (Sheep)super.clone();
} catch (Exception e) {}
return sheep;
}
}
//深拷贝把要复制的对象所引用的对象都复制了一遍
//1.重写clone方法来实现深拷贝,然后对所有引用属性进行拷贝
//2.通过对象序列化实现深拷贝(推荐)
public class Client {
public static void main(String[] args) throws Exception {
Sheep sheep = new Sheep("tom");
Sheep firend = new Sheep("jack");
sheep.setFriend(firend);
//方式1 完成深拷贝
// Sheep sheep2 = (Sheep)sheep.clone();
// System.out.println("firend=" + firend + ",sheep2.friend=" + sheep2.getFriend());
//方式2 完成深拷贝
Sheep sheep2 = (Sheep)sheep.deepClone();
System.out.println("firend=" + firend + ",sheep2.friend=" + sheep2.getFriend());
}
}
class Sheep implements Cloneable,Serializable {
private String name;//基本数据类型直接复制
private Sheep friend; //引用数据类型引用传递
public Sheep(String name) { this.name = name; }
public String getName() { return name; }
public Sheep getFriend() { return friend; }
public void setFriend(Sheep friend) { this.friend = friend; }
@Override
protected Object clone() {//克隆该实例,使用默认的clone方法来完成
Sheep sheep = null;
try {
sheep = (Sheep)super.clone();
sheep.setFriend((Sheep) friend.clone());
} catch (Exception e) {}
return sheep;
}
//深拷贝 - 方式2 通过对象的序列化实现 (推荐)
public Object deepClone() {
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);
Sheep copyObj = (Sheep) ois.readObject();
return copyObj;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {//关闭流
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (Exception e2) {
System.out.println(e2.getMessage());
}
}
}
}
3.1.5. 建造者模式
- 建造者模式,将组成部分相似的复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。
- 建造者模式是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节
public class Client{
public static void main(String[] args) {
System.out.println(new ProductDricter().build(new ProductBuilder()));
}
}
//Product(产品角色): 一个具体的产品对象。
class Product{
private String name;
private String price;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getPrice() { return price; }
public void setPrice(String price) { this.price = price; }
public String toString() { return "Product{name=" + name + ", price=" + price + "}"; }
}
//抽象建造者: 创建一个Product对象的各个部件指定的 接口/抽象类
abstract class Builder{
protected Product product = new Product();
abstract void buildName();
abstract void bulidPrice();
public Product getProduct(){return product;}
}
//多个具体建造者
class ProductBuilder extends Builder{
public void buildName(){this.product.setName("炸鸡");}
public void bulidPrice(){this.product.setPrice("10元");}
public Product getProduct(){return product;}
}
//指挥者 传入不同的制造者
class ProductDricter {
public Product build(Builder builder){
builder.buildName();
builder.bulidPrice();
return builder.getProduct();
}
}
总结
本文介绍了的设计模式使用,如有问题欢迎私信和评论