java必知必会-设计模式(上)


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();
    }
}

总结

本文介绍了的设计模式使用,如有问题欢迎私信和评论

  • 52
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程岁月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值