设计模式的好处以及单例模式、原型模式详解
使用设计模式的好处:
高内聚,低耦合
代码重用性:相同功能,不用多次编写
可读性:编程规范,便于他人阅读和理解
可扩展性(可维护性):新增需求功能时,非常方便
可靠性:新增功能后,不影响原来的功能
设计模式分三种类型(23种):
创建型模式:单例模式、原型模式、工厂模式、抽象工厂模式、建造者模式
结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式
行为型模式:模板方法模式、命令模式、访问者模式、观察者模式、迭代器模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责模式(责任链模式)
设计模式的七大原则:
单一职责:一个类只负责一项职责,各司其职
接口隔离:最小接口原则,不去实现不用的接口方法,对接口进行拆分
依赖倒置:面对接口编程。抽象不应该依赖细节,细节应该起来抽象
里氏替换:使用继承时,子类尽量不要重写父类的方法,可通过聚合、组合、依赖来解决问题
开闭原则 ocp:扩展开放(提供方),对修改关闭(使用方)
迪米特法则:降低类间耦合度
合成复用:尽量使用合成/聚合的方式,而不是使用
设计模式在软件中哪里使用:
面向对象(OO) -> 功能模式 [设计模式+算法(数据结构)] -> 框架 [多种设计模式 ] -> 架构 [服务器集群]
面试官一般会问:项目中使用过哪些设计模式,是如何使用的,解决了哪些问题
单例模式(8中实现方式):
饿汉式(静态常量)
class Singleton {
// 1.构造器私有化(防止new)
private Singleton() {}
// 2.类的内部创建对象
private final static Singleton singleton = new Singleton();
// 3.向外暴露一个静态的公共方法 getInstance
public static Singleton getInstance(){
return singleton;
}
}饿汉式(静态代码块量)
class Singleton {
// 1.构造器私有化(防止new)
private Singleton() {}
// 2.类的内部创建对象
private static Singleton singleton;
static { // 通过静态代码块创建单例对象
singleton = new Singleton();
}
// 3.向外暴露一个静态的公共方法 getInstance
public static Singleton getInstance(){
return singleton;
}
}
// -----------------
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1 == instance2); // true,同一实例
// -----------------
/** 饿汉式优缺点
优点:写法简单,类加载的时候就完成实例化,避免了线程同步的问题
缺点:类加载的时候就完成实例化,没有达到懒加载的效果。如果从始到终都没用过此实例,会造成内存浪费
*/懒汉式(线程不安全), 在开发中不使用该方式!!!
class Singleton {
private Singleton() {}
private static Singleton singleton;
// 3.只有在条用该方法时,才会去创建实例化对象 (而饿汉式是在类加载时就完成实例化)
public static Singleton getInstance(){
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
/** 该方式优缺点
优点:起到懒加载的效果,但只能在单线程下使用
缺点:如果在多线程下,一个线程进入if (singleton == null),还未来得及创建,另一线程也通过判断条件,这是便会产生多个实例。在开发中不使用该方式!!!
*/懒汉式(线程安全,同步方法), 实际开发中不推荐使用。
class Singleton {
private Singleton() {}
private static Singleton singleton;
// 3.只有在条用该方法时,才会去创建实例化对象 (使用synchronized安全锁,保证线程安全问题)
public static synchronized Singleton getInstance(){
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
/** 该方式优缺点
优点:起到懒加载的效果,也解决了线程安全问题
缺点:效率低。其实实例化对象只需要第一次做,之后直接返回对象即可。实际开发中不推荐使用。
*/懒汉式(同步代码块), 在开发中不使用该方式,是无实际意义的!!!
class Singleton {
private Singleton() {}
private static Singleton singleton;
// 3.只有在条用该方法时,才会去创建实例化对象
public static Singleton getInstance(){
if (singleton == null) {
synchronized (Singleton.class) { //使用synchronized同步代码块,保证线程安全问题
singleton = new Singleton();
}
}
return singleton;
}
}
// 这种写法是想解决上面方式效率低的问题,但却连线程安全都没达到双重检查(线程安全,懒加载,效率高), 推荐使用
class Singleton {
private Singleton() {}
// 添加 volatile 关键字:singleton一旦有变化,就会刷新到主内存中,让其他使用的线程可以知道,同时在一定程度上可以达到同步效果
private static volatile Singleton singleton;
// 3.双重检查
public static Singleton getInstance(){
if (singleton == null) { // 第一次判断是否null
synchronized (Singleton.class) { // 使用synchronized同步代码块,保证线程安全问题
if (singleton == null) { // 第二次判断是否null
singleton = new Singleton();
}
}
}
return singleton;
}
}
//Double-check概念在多线程中经常使用的静态内部类(线程安全,懒加载,效率高), 推荐使用
// 静态内部类的特点:1 当外部类加载时,静态内部类是不会被加载的;2 当调用静态类方法时,静态内部类才会被加载,而且只会加载一次,是线程安全的
// 也就是说,静态内部类,既可以达到懒加载的效果,也可以保证线程安全
class Singleton {
private Singleton() {}
// 添加 volatile 关键字:singleton一旦有变化,就会刷新到主内存中,让其他使用的线程可以知道,同时在一定程度上可以达到同步效果
private static volatile Singleton singleton;
// 通过静态内部类来实例化
private static class SingletonInstance {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance(){
return SingletonInstance.INSTANCE;
}
}枚举,推荐使用
enum Singleton{
INSTANCE;
public void method(){
System.out.println("hello");
}
}
// -----------------
Singleton instance1 = Singleton.INSTANCE;
Singleton instance2 = Singleton.INSTANCE;
System.out.println(instance1 == instance2); // true
// -----------------
// 借助JDK1.5添加的枚举来实现单例模式。不仅能避免多线程同步问题,而且还能防止反序列化重新创建对象
使用单例模式的原因 和 注意细节:
单例模式保证了 系统内存中,一个类只存一个对象,节省系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提供系统性能
当想实例化一个单例对象时,必须使用相对的获取对象的方法,而不是new
原型模式 Prototype:
用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象
原型模式是一种创建型设计模式,允许一个对象在创建另一个可定制的对象,无需知道创建的细节
工作原理:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝他们自己来实现创建,即 对象.clone()
浅拷贝(默认)
对于基本数据类型,直接进行值的拷贝
对于引用类型,只是引用传递,指向同一个实例。
public class Sheep implements Cloneable {
private String name;
private String color;
public Sheep(String name, String color) {
this.name = name;
this.color = color;
}
@Override
protected Sheep clone() throws CloneNotSupportedException {
return (Sheep)super.clone();
}
}
// 普通写法 ---------------
Sheep sheep1 = new Sheep();
Sheep sheep2 = new Sheep();
// 原型模式 ---------------
Sheep sheep3 = sheep1.clone();
System.out.println(sheep1 == sheep3); // false深拷贝
对于基本数据类型,直接进行值的拷贝
对于引用类型,会申请存储空间,进行整个对象的拷贝,而不是仅拷贝引用地址。
深拷贝实现方式1:重写clone方法
public class Sheep implements Cloneable, Serializable {
private String name;
private String color;
private Sheep friend;
public Sheep(String name, String color) {
this.name = name;
this.color = color;
}
@Override
protected Sheep clone() throws CloneNotSupportedException {
// 先对基本类型和String进行克隆
Sheep sheep = (Sheep)super.clone();
// 在对引用类型进行单独处理
sheep.friend = (Sheep)friend.clone();
return sheep;
}
}
深拷贝实现方式2:对象序列化(推荐使用)
public Object SerClone(){
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 sheep = (Sheep)ois.readObject();
return sheep;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
try {
bos.close();oos.close();bis.close();ois.close();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
};
// bean.xml
<bean id="user" class="com.auv.bean.User" scope="prototype">
// java
ClassPathXmlApplicationContext("bean.xml");
Object bean = applicationContext.getBean("user")

浙公网安备 33010602011771号