目录
面向对象七大原则
- 开闭原则:对扩展开放,对修改关闭
- 里氏替换原则:继承必须确保父类所拥有的性质在子类中依然成立
- 依赖倒置原则:要面向接口编程,不要面向实现编程
- 单一职责原则:控制类的粒度大小、将对象解耦、提高其内聚性
- 接口隔离原则:要为各个类建立它们需要的专用接口
- 迪米特法则:只与你的直接朋友交谈,不跟陌生人说话
- ** 合成复用原则**: 尽量先使用组合或者聚合等关联关系来实现,其次再考虑使用继承关系来实现
创建型模式
单例模式
饿汉式单例
- 构造器私有
- 一开始就加载对象
- 可能会浪费空间
public class Hungry{
//一开始就加载对象
private finall static Hungry hungry = new Hungry();
//构造器私有
private Hungry(){
}
//通过方法获取对象
public static Hungry getHungry(){
return hungry;
}
}
懒汉式单例
- 要用的时候再加载
- 单线程可以,多线程的时候要加锁
//懒汉式
public class Lazy{
//先定义对象,并不实例化
private volatile static Lazy lazy;
//构造器私有
private Lazy(){
synchronized(Lazy.class){
if(lazy!=null){
throw RuntimeException("要试图通过反射去破坏单例")
}
}
}
//通过方法获取对象:双重检测锁模式,DCL懒汉式
public static Lazy getLazy(){
if(lazy==null){
synchronized (Lazy.class) {
if(lazy==null){
lazy=new Lazy();
/**
* 不是一个原子性操作
* 1. 分配内存空间
* 2. 执行构造方法,初始化对象
* 3. 把这个对象指向空间
* 可能指令重排,所以在对象前加:volatile
**/
}
}
}
return lazy;
}
}
静态内部类实现单例
- 通过静态内部类实现
public class StaSign{
private StaSign(){
}
public static StaSign getInstance(){
return InnerClass.STASIGN
}
public static class InnerClass{
private static finall StaSign STASIGN= new StaSign();
}
}
- 上面的两种方法都可以通过java反射破解
枚举单例
- 枚举里面没有无参构造,只有有参构造
- 使用枚举可以解决java反射破解
public enum EnumSingle{
INSTANCE;
public EnumSingle getInstance(){
return INSTANCE;
}
}
工厂模式(Factory)
- 创建对象统一管理和控制,创建者和调用者分离
- 实例化对象不使用new,用工厂方法代替
简单(静态)工厂模式
- 用来生产同一级结构中的任意产品
- 增加一个新产品,如果不修改代码,做不到,不满足闭合原则
public interface Car{
void getName();
}
public class Car1 import Car{
void getName(){
System.out.println("car1");
}
}
public class Car2 import Car{
void getName(){
System.out.println("car2");
}
}
//建立一个工厂
public class CarFactory{
public static Car getCar1(){
return new Car1();
}
public static Car getCar2(){
return new Car2();
}
}
工厂方法模式
- 用来生产同一级结构中的固定产品
- 把工厂提取出一个抽象类
- 为每一个对象创建一个工厂:变的复杂了
- 这个新增功能的时候,就不用修改原来的代码。满足开闭原则
public interface Car{
void getName();
}
public class Car1 import Car{
@verride
void getName(){
System.out.println("car1");
}
}
public class Car2 import Car{
@verride
void getName(){
System.out.println("car2");
}
}
//工厂方法模式
public interface CarFactory{
Car getCar();
}
public class Car1Factory import CarFactory{
@Verride
Car getCar(){
return new Car1();
}
}
public class Car2Factory import CarFactory{
@Verride
Car getCar(){
return new Car2();
}
}
抽象工厂模式
- 围绕一个超级工厂创建其他工厂
- 不能增加产品,但是可以增加产品族
- 规定了所有可能被创建的产品的集合,产品族中扩展新的产品很困难
- 增加了系统的抽象性和理解难度
//抽象工厂模式
public interface Car{
void start();
void run();
void stop();
}
public class WuLin import Car{
@verride
void start(){
System.out.println("start");
}
@verride
void run(){
System.out.println("run");
}
@verride
void stop(){
System.out.println("stop");
}
}
public interface CarFactory{
public CarFactory getCarFactory();
}
public class WuLinFactory import CarFactory{
@Verride
public CarFactory getWuLinCar(){
return new WuLin();
}
}
建造者模式(Builder)
- 建造者模式也属于创建模式,它提供一种创建对象的最佳方式
- 定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
- 作用:在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象
- 用户只需要给出指定对象的类型和内容,建造者模式负责顺序创建复杂对象(把内部的建造过程和细节隐藏起来)
产品:
public class Protect {
String A;
String B;
String C;
String D;
public String getA() {
return A;
}
public void setA(String a) {
A = a;
}
public String getB() {
return B;
}
public void setB(String b) {
B = b;
}
public String getC() {
return C;
}
public void setC(String c) {
C = c;
}
public String getD() {
return D;
}
public void setD(String d) {
D = d;
}
@Override
public String toString() {
return "protect{" +
"A='" + A + '\'' +
", B='" + B + '\'' +
", C='" + C + '\'' +
", D='" + D + '\'' +
'}';
}
}
生产者:
public interface Builder {
Builder builderA();
Builder builderB();
Builder builderC();
Builder builderD();
Protect getProtect();
}
public class Worker implements Builder{
Protect protect = new Protect();
public Protect getProtect(){
return protect;
}
public Builder builderA() {
protect.setA("A");
return this;
}
public Builder builderB() {
protect.setB("B");
return this;
}
public Builder builderC() {
protect.setC("C");
return this;
}
public Builder builderD() {
protect.setD("D");
return this;
}
}
指挥者:
- 我们可以在指挥者里改变顺序
public class Director {
public Protect BuildProtect(Builder builder){
builder.builderA();
builder.builderB();
builder.builderC();
builder.builderD();
return builder.getProtect();
}
}
测试:
- 只用调用指挥者
class Test {
public static void main(String[] args) {
Director director=new Director();
Protect protect = director.BuildProtect(new Worker());
System.out.println(protect.toString());
}
}
改进建造者模式
-
通常用户就是指挥者,指挥者可以去掉
-
给产品一个默认值
String A="A";
String B="B";
String C="C";
String D="D";
- 接口传入赋值参数,如果不赋值,就是默认值
public interface Builder {
Builder builderA(String msg);
Builder builderB(String msg);
Builder builderC(String msg);
Builder builderD(String msg);
Protect getProtect();
}
- 测试
class Test {
public static void main(String[] args) {
Worker worker=new Worker();
worker.builderA("D")
.builderB("C")
.builderC("B")
.builderD("A");
Protect protect = worker.getProtect();
System.out.println(protect.toString());
}
}
- 应用场景:
- 需要生成的产品对象有复杂的内部结构,这些产品对象具备共性
- 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品
- 适用于一个具有较多的零件(属性)的产品(对象)的创建过程
原型模式(Prototyte)
- 克隆对象(clone())
- 实现一个接口:Cloneable
- 重写一个方法:clone
//实现一个接口:Cloneable
//重写一个方法:clone
public class Video implements Cloneable {
private String name;
private Date data;
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getData() {
return data;
}
public void setData(Date data) {
this.data = data;
}
public Video(String name, Date data) {
this.name = name;
this.data = data;
}
@Override
public String toString() {
return "demo{" +
"name='" + name + '\'' +
", data=" + data +
'}';
}
}
- 测试:直接调用clone方法就可以实现了
public static void main(String[] args) throws CloneNotSupportedException {
Date date=new Date();
Video v1=new Video("huang",date);
System.out.println(v1.toString());
Video clone =(Video) v1.clone();
System.out.println(clone.toString());
}
以上方法只是浅克隆,对象里面的data对象,指向的还是同一个
- 类似于C++里面的浅拷贝深拷贝的概念
- 要实现深克隆,改变clone方法
@Override
public Object clone() throws CloneNotSupportedException {
Object clone = super.clone();
Video video=(Video) clone;
//将这个对象的属性也进行克隆
video.data= (Date) this.data.clone();
return clone;
}
- spring Bean使用的单例模式+原型模式
- 原型模式+工厂模式:在工厂创建对象的时候使用克隆更快