
/**
* @author zero
* @description HungrySingleton 饿汉模式
* @date 2022/4/25 15:09
*/
public class HungrySingleton {
public static void main(String[] args) {
Singleton instance1 = Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
}
class Singleton{
// 1、构造器私有化
private Singleton() { }
// 2、提前创建好对象
private final static Singleton singleton = new Singleton();
// 3、提供访问对象的方法
public static Singleton getInstance() {
return singleton;
}
}
1.1.2 静态代码块优缺点说明:
优点:写法简单,就是在类加载的时候完成对象实例化,避免了线程同步问题
缺点:在类加载的时候完成对象实例化,没有达到懒加载的效果,如果此对象一直未使用,则可能会造成内存浪费
public class HungrySingleton2 {
public static void main(String[] args) {
Singleton2 instance1 = Singleton2.getInstance();
Singleton2 instance2 = Singleton2.getInstance();
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
}
class Singleton2{
private static Singleton2 instance;
// 1、构造器私有化
private Singleton2() {}
static {
// 2、提前创建好对象
instance = new Singleton2();
}
// 3、提供访问对象的方法
public static Singleton2 getInstance() {
return instance;
}
}
1.2 懒汉式(3种)
1.2.1 线程不安全
public class LazySingletonUnSafe {
public static void main(String[] args) {
Singleton instance1 =Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1 == instance2);
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
}
class Singleton{
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
// 在使用的时候才进行实例化
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
1.2.2 线程安全优缺点说明:
优点:起到了懒加载的效果
缺点:多线程环境下是不安全的,实际开发种,不推荐这种写法
public class LazySingletonSafe {
public static void main(String[] args) {
Singleton1 instance1 =Singleton1.getInstance();
Singleton1 instance2 = Singleton1.getInstance();
System.out.println(instance1 == instance2);
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
}
class Singleton1{
private static Singleton1 instance;
private Singleton1() {}
public static synchronized Singleton1 getInstance() {
// 加synchronized使得实例化的过程线程安全
if (instance == null) {
instance = new Singleton1();
}
return instance;
}
}
1.2.3 同步代码块优缺点说明:
优点:解决了线程不安全问题
缺点:每次在获取对象实例的时候多要加锁,效率比较低,实际开发种也不推荐这种用法
public class LazySingletonBlock {
private static LazySingletonBlock instance;
private LazySingletonBlock() {}
public static LazySingletonBlock getInstance() {
if (instance == null) {
// 此处加锁是不能保证线程安全的
synchronized (LazySingletonBlock.class) {
instance = new LazySingletonBlock();
}
}
return instance;
}
}
1.3 双重检查说明:
这种同步方式不能起到线程安全的作用
public class DCSingleton {
public static void main(String[] args) {
Singleton instance1 =Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1 == instance2);
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
}
class Singleton {
private static volatile Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
1.4 静态内部类说明:
Double-Check进行了两次if检查,保证了线程安全,即对象只实例化一次,同时也保证了对象的延迟加载,提升效率,在开发种推荐这种方式。
public class StaticInnerClassSingleton {
public static void main(String[] args) {
Singleton instance1 =Singleton.getInstance();
Singleton instance2 = Singleton.getInstance();
System.out.println(instance1.hashCode());
System.out.println(instance2.hashCode());
}
}
class Singleton{
private Singleton() {}
private static class SingletonInstance{
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonInstance.INSTANCE;
}
}
1.5 枚举类说明:
这种方式采用了类加载的机制来保证初始化实例时只有一个线程
利用静态内部类的特点实现延迟加载,且是线程安全的,推荐使用
public class EnumSingleton {
public static void main(String[] args) {
Singleton instance = Singleton.INSTANCE;
Singleton instance2 = Singleton.INSTANCE;
System.out.println(instance.hashCode());
System.out.println(instance2.hashCode());
instance.say();
}
}
enum Singleton{
/**
* 单例对象
*/
INSTANCE;
public void say() {
System.out.println("this is a enum class");
}
}
2、工厂模式 2.1简单工厂模式说明:
借助枚举来实现单例模式,不仅能避免线程同步问题,而且还能防止反序列化重新创建新的对象。推荐使用。
简单工厂包含三种角色:
- 抽象产品:定义产品的规范,描述了产品的主要特性和功能
- 具体产品:实现或继承抽象产品的子类
- 具体工厂:提供了创建产品的方法,调用者通过该方法来创建产品
以造汽车为例,分别建立这三种角色所代表的类。
public abstract class Car {
public abstract void setCarName();
public void run() {
setCarName();
System.out.println("汽车跑起来!!");
}
}
public class AudiCar extends Car{
@Override
public void setCarName() {
System.out.println("奥迪汽车");
}
}
public class BenzCar extends Car {
@Override
public void setCarName() {
System.out.println("奔驰汽车");
}
}
public class AutoCar extends Car {
@Override
public void setCarName() {
System.out.println("奥拓汽车");
}
}
public class CarSimpleFactory {
Car car = null;
public Car createCar(String brand) {
if ("Audi".equals(brand)) {
car = new AudiCar();
} else if ("Benz".equals(brand)) {
car = new BenzCar();
} else {
car = new AutoCar();
}
return car;
}
}
public class CarStore {
public static void main(String[] args) {
CarSimpleFactory factory = new CarSimpleFactory();
Car audi = factory.createCar("Audi");
audi.run();
}
}
2.2工厂方法模式优缺点说明:
优点:封装了创建对象的过程,可以通过参数直接获取对象,这样就把对象的创建和业务逻辑分开,降低了代码耦合度,更容易实现扩展
缺点:增加新产品时还需要修改工厂类的代码,如上面代码中if-else,违背了开闭原则
工厂方法相比于简单工厂而言,多了一个工厂的抽象,即将创建对象的工厂进行抽象,由不同的实现类型来创建不同的对象。类图如下:
抽象产品类与上边的简单工厂一样,下面展示不同的代码之处:
public abstract class CarFactory {
public abstract Car createCar(String type);
}
public class AudiCarFactory extends CarFactory{
@Override
public Car createCar(String type) {
Car car = null;
if ("SUV".equals(type)) {
car = new AudiSuvCar();
} else {
car = new AudiSportCar();
}
return car;
}
}
public class AudiSportCar extends Car {
@Override
public void setCarName() {
System.out.println("奥迪跑车");
}
}
public class AudiSuvCar extends Car {
@Override
public void setCarName() {
System.out.println("奥迪SUV");
}
}
public class CarStore {
public static void main(String[] args) {
// 创建对象使用具体的工厂
CarFactory audiCarFactory = new AudiCarFactory();
Car suv = audiCarFactory.createCar("SUV");
suv.run();
}
}
2.3抽象工厂模式
抽象工厂模式是将创建具体类型对象的工厂的共性进行了抽象,形成了更上层的类,同时根据不同类型的工厂提供不同能力的对象创建,与工厂方法模式相比,多了一层抽象,使得不同的业务下沉到抽象工厂,上层提供一个统一的工厂接口,类图如下:
public interface CarFactory {
Car createCar(String type);
void modifyCar(Car car);
}
public abstract class CreateAudiCarFactory implements CarFactory {
@Override
public Car createCar(String type) {
Car car = null;
if ("SUV".equals(type)) {
car = new AudiSuvCar();
} else {
car = new AudiSportCar();
}
return car;
}
}
public class AudiCarFactory extends CreateAudiCarFactory{
@Override
public void modifyCar(Car car) {
System.out.println("修理奥迪汽车!!!");
}
}
public class CarStore {
public static void main(String[] args) {
// 创建对象使用具体的工厂
CarFactory audiCarFactory = new AudiCarFactory();
Car suv = audiCarFactory.createCar("SUV");
suv.run();
audiCarFactory.modifyCar(suv);
}
}
4、原型模式抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。
原型模式是一个比较简单的模式,在JDK中Object类提供了一个clone()方法,其子类只需要实现Clonealbe接口并重写clone()方法就能实现对象的复制问题,原型模式通过clone方法创建对象是通过复制内存中的流实现的,故在使用时不会调用类的构造函数。这种方式默认提供的复制对象的能力为浅拷贝,如果需要深拷贝对象,则需要定制实现。
public class Person implements Cloneable{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 省略get/set/toString方法
@Override
protected Person clone() {
Person person = null;
try {
person = (Person) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return person;
}
}
public class Client {
public static void main(String[] args) {
Person person = new Person("Zero", 18);
Person clone = person.clone();
System.out.println(person);
System.out.println(clone);
}
}
5、建造者模式优缺点说明:
优点:性能优良,原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。
缺点:逃避构造函数的约束,这个也不能说是缺点,看实际的使用场景吧
建造者模式也叫生成器模式,表示将一个复杂对象的创建与它的表示分开,如创建一个跑车对象,只需要将轮子,方向盘,发动机进行组装即可,无需关心各个组件是如何创建的。建造者模式有四种角色:
- Product(产品角色):一个具体的产品对象
- Builder(抽象建造者):创建一个Product对象的各个组件指定的接口/抽象类
- ConcreBuilder(具体建造者):实现接口,构建和装配各个组件
- Director(指挥者):构建一个使用Builder接口的对象,它主要是用于创建一个复杂的对象。主要有两个作用:一是隔离了客户与对象的生产过程;二是负责控制产品对象的生产过程
public class House {
private String basic;
private String wall;
private String roofed;
// 省略get/set方法
}
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 CommonHouse extends HouseBuilder{
@Override
public void buildBasic() {
System.out.println("普通房子打地基3米");
}
@Override
public void buildWalls() {
System.out.println("普通房子砌墙10cm");
}
@Override
public void roofed() {
System.out.println("普通房子封顶");
}
}
public class HouseDirector {
HouseBuilder builder = null;
public HouseDirector(HouseBuilder builder) {
this.builder = builder;
}
// 具体产品的创建过程,过程是不对外暴露的
public House constructHouse() {
builder.buildBasic();
builder.buildWalls();
builder.roofed();
return builder.buildHouse();
}
}
public class Client {
public static void main(String[] args) {
CommonHouse commonHouse = new CommonHouse();
HouseDirector director = new HouseDirector(commonHouse);
House house = director.constructHouse();
System.out.println(house);
}
}
二、结构型(7种) 1、适配器模式优缺点说明:
优点:封装性,使用该模式使客户端可以不用知道产品内部组成细节;建造者独立,容易扩展;便于控制细节风险,由于具体的建造者是独立的,因此可以对建造过程逐步细化,而不对其他模块产生影响
缺点:产生多个建造类,有可能造成类爆炸的问题
适配器模式将某个类的接口转换成客户端期望给的另一个接口表示,主要的目的是兼容性,让原本因接口不匹配不能一起工作的两个类可以协同工作。主要分为三类:类适配器模式、对象适配器模式,接口适配器模式。
1.1类适配器模式public class Voltage220V {
public int output220v() {
int src = 220;
System.out.println("输出220V电压");
return src;
}
}
public interface IVoltage5V {
int output5V();
}
public class VoltageAdapter extends Voltage220V implements IVoltage5V {
@Override
public int output5V() {
int srcV = output220v();
int dstV = srcV / 44;
return dstV;
}
}
public class Phone {
public void charge(IVoltage5V voltage5V) {
if (voltage5V.output5V() == 5) {
System.out.println("电压正常,可以充电。。。。");
} else {
System.out.println("电压不正常,无法充电");
}
}
}
public class Client {
public static void main(String[] args) {
// 类适配器模式
Phone phone = new Phone();
phone.charge(new VoltageAdapter());
}
}
1.2对象适配器模式
根据合成复用原则,在系统中尽量使用关联来替代继承关系,故上边的类适配器模式中的继承不太友好,为了解决此问题,将适配器类中的继承改为持有源接口的实例,以此来符合合成复用原则。
public class VoltageAdapter implements IVoltage5V {
private Voltage220V voltage220V;
@Override
public int output5V() {
int dstv = 0;
if (voltage220V != null) {
int srcV = voltage220V.output220v();
int dstV = srcV / 44;
}
return dstv;
}
public void setVoltage220V(Voltage220V voltage220V) {
this.voltage220V = voltage220V;
}
}
public class Client {
public static void main(String[] args) {
// 对象适配器模式
Phone phone = new Phone();
VoltageAdapter voltageAdapter = new VoltageAdapter();
voltageAdapter.setVoltage220V(new Voltage220V());
phone.charge(voltageAdapter);
}
}
1.3接口适配器模式
使用抽象类实现接口的所有方法,同时将抽象类作为适配器类提供给客户端使用,保证了客户端无需实现接口的所有实现,只需实现自己关心的方法即可。
public interface Interface {
void operation();
void operation1();
void operation2();
}
public abstract class AbstractAdapter implements Interface{
@Override
public void operation() {
}
@Override
public void operation1() {
}
@Override
public void operation2() {
}
}
public class Client {
public static void main(String[] args) {
// 接口适配器模式
AbstractAdapter adapter = new AbstractAdapter(){
@Override
public void operation() {
System.out.println("覆盖默认方法实现");
}
};
adapter.operation();
}
}
2、桥接模式优缺点说明:
适配器模式可以让两个没有任何关系的类在一起运行,只要适配器这个角色能够搞定他们就成;增加了类的透明性,提高了类的复用度,灵活性好
桥接模式是指将实现与抽象放在两个不同类层次中,使两个类可以独立改变。以不同品牌不同样式手机为例。
public interface Brand {
void open();
void call();
void close();
}
public class Vivo implements Brand{
@Override
public void open() {
System.out.println("Vivo手机开机");
}
@Override
public void call() {
System.out.println("Vivo手机打电话");
}
@Override
public void close() {
System.out.println("Vivo手机关机");
}
}
public class Xiaomi implements Brand{
@Override
public void open() {
System.out.println("小米手机开机");
}
@Override
public void call() {
System.out.println("小米手机打电话");
}
@Override
public void close() {
System.out.println("小米手机关机");
}
}
public abstract class Phone {
// 聚合了接口业务
private Brand brand;
public Phone(Brand brand) {
this.brand = brand;
}
protected void open() {
this.brand.open();
}
protected void call() {
this.brand.call();
}
protected void close() {
this.brand.close();
}
}
public class FoldedPhone extends Phone{
public FoldedPhone(Brand brand) {
super(brand);
}
public void open() {
super.open();
}
public void call() {
super.call();
}
public void close() {
super.close();
}
}
public class Client {
public static void main(String[] args) {
Phone phone = new FoldedPhone(new Vivo());
phone.open();
phone.call();
phone.close();
System.out.println("=================");
Phone phone1 = new FoldedPhone(new Xiaomi());
phone1.open();
phone1.call();
phone1.close();
}
}
如上代码所示,如果想增加一种样式的手机,只需要继承抽象类Phone后就能实现手机对应的全部功能。同时在JDBC的实现模式中就应用了桥接模式,不同类型数据库实现了相同的JDBC接口业务。
优缺点说明:
抽象和实现分离,优秀的扩展能力,实现细节对客户透明。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)