设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的充分理解。
正确使用设计模式具有以下优点:
意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
主要解决:一个全局使用的类频繁地创建与销毁。
何时使用:当您想控制实例数目,节省系统资源的时候。
如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。
关键代码:构造函数是私有的。
package com.lee; // 饿汉式单例 public class Hungry { private Hungry() { } private final static Hungry HUNGRY = new Hungry(); public static Hungry getInstance() { return HUNGRY; } /* 可能会浪费空间 private byte[] data1 = new byte[1024 * 1024]; private byte[] data2 = new byte[1024 * 1024]; private byte[] data3 = new byte[1024 * 1024]; private byte[] data4 = new byte[1024 * 1024]; */ }
package com.lee; // 懒汉式单例 public class LazyMan { private static boolean password = false; private LazyMan() { // synchronized (LazyMan.class) { // if (lazyMan != null) { // throw new RuntimeException("不要试图使用反射破坏 异常"); // } // } synchronized (LazyMan.class) { if (password == false) { password = true; } else { throw new RuntimeException("不要试图使用反射破坏 异常"); } } } private static LazyMan lazyMan; // public static LazyMan getInstance() { // if (lazyMan == null) { // lazyMan = new LazyMan(); // } // return lazyMan; // } // 双重检测锁模式的懒汉式单例 DCL 懒汉式单例 public static LazyMan getInstance() { if (lazyMan == null) { synchronized (LazyMan.class) { if (lazyMan == null) { lazyMan = new LazyMan(); /* lazyMan = new LazyMan(); 不是原子性的操作 1. 分配内存空间 2. 执行构造方法,初始化对象 3. 把这个对象指向这个空间 期望执行顺序 123 实际执行可能 132 ... */ } } } return lazyMan; } // 只适用于单线程 // 多线程并发 public static void main(String[] args) { for (int i = 0; i < 10; i++) { new Thread(() -> { LazyMan.getInstance(); }).start(); } } } class TestLazyMan { public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { // LazyMan instance = LazyMan.getInstance(); Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null); // 可获得 private 属性方法 declaredConstructor.setAccessible(true); LazyMan instance2 = declaredConstructor.newInstance(); LazyMan instance3 = declaredConstructor.newInstance(); // System.out.println(instance == instance2); System.out.println(instance2 == instance3); } }
单例不安全,可以被反射破坏
package com.lee; // 静态内部类 public class Holder { private Holder() { } public static Holder getInstance() { return InnerClass.HOLDER; } public static class InnerClass { private static final Holder HOLDER = new Holder(); } }
枚举单例不可破坏
package com.lee; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; // 枚举 public enum EnumSingle { INSTANCE; public EnumSingle getInstance() { return INSTANCE; } } class TestEnum { public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { EnumSingle instance1 = EnumSingle.INSTANCE; //Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(null); // java.lang.NoSuchMethodException: com.lee.EnumSingle.<init>() Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class, int.class); // Cannot reflectively create enum objects // at java.lang.reflect.Constructor.newInstance(Constructor.java:417) // 得出结论: 枚举单例不可破坏 declaredConstructor.setAccessible(true); EnumSingle instance3 = declaredConstructor.newInstance(); EnumSingle instance2 = EnumSingle.INSTANCE; System.out.println(instance1); System.out.println(instance2); System.out.println(instance3); } }
接口 car
public interface Car { void name(); }
实现类一
public class WuLing implements Car{ @Override public void name() { System.out.println("五菱宏光"); } }
实现类二
public class Tesla implements Car{ @Override public void name() { System.out.println("特斯拉"); } }
public class CarFactory { public static Car getCar(String car) { if (car.equals("五菱")) { return new WuLing(); } else if (car.equals("特斯拉")) { return new Tesla(); } else { return null; } } }
public class Consumer { public static void main(String[] args) { Car wuLing = CarFactory.getCar("五菱"); Car tesla = CarFactory.getCar("特斯拉"); wuLing.name(); tesla.name(); } }
应用举例
WuLingFactory
public class WuLingFactory implements CarFactory{ @Override public Car getCar() { return new WuLing(); } }
TeslaFactory
public class TeslaFactory implements CarFactory{ @Override public Car getCar() { return new Tesla(); } }
// 工厂方法模式 public interface CarFactory { Car getCar(); }
public class Consumer { public static void main(String[] args) { Car wuLing = new WuLingFactory().getCar(); Car tesla = new TeslaFactory().getCar(); wuLing.name(); tesla.name(); Car mobai = new MobaiFactory().getCar(); mobai.name(); } }
结构复杂度、代码复杂度、编程复杂度、管理上的复杂度 都是简单工厂好一些
// 超级工厂 public interface IProductFactory { // 生产手机 IphoneProduct phoneProduct(); // 生产路由器 IRouterProduct RouterProduct(); } // 手机产品 public interface IphoneProduct { void start(); void shutdown(); void callup(); void sengMS(); } // 路由器产品 public interface IRouterProduct { void start(); void shutdown(); void openWifi(); void setting(); } // MiFactory public class MiFactory implements IProductFactory{ @Override public IphoneProduct phoneProduct() { return new MiPhone(); } @Override public IRouterProduct RouterProduct() { return new MiRouter(); } } public class HWFactory implements IProductFactory{ @Override public IphoneProduct phoneProduct() { return new HWPhone(); } @Override public IRouterProduct RouterProduct() { return new HWRouter(); } }
具体产品
// MiPhone public class MiPhone implements IphoneProduct{ @Override public void start() { System.out.println("小米手机开机"); } @Override public void shutdown() { System.out.println("小米手机关机"); } @Override public void callup() { System.out.println("小米手机打电话"); } @Override public void sengMS() { System.out.println("小米手机发短信"); } } // MiRouter public class MiRouter implements IRouterProduct{ @Override public void start() { System.out.println("小米路由器开启"); } @Override public void shutdown() { System.out.println("小米路由器关闭"); } @Override public void openWifi() { System.out.println("小米路由器打开wifi"); } @Override public void setting() { System.out.println("小米路由器设置"); } } // HWPhone public class HWPhone implements IphoneProduct{ @Override public void start() { System.out.println("华为手机开机"); } @Override public void shutdown() { System.out.println("华为手机关机"); } @Override public void callup() { System.out.println("华为手机打电话"); } @Override public void sengMS() { System.out.println("华为手机发短信"); } } // public class HWRouter implements IRouterProduct{ @Override public void start() { System.out.println("华为路由器开启"); } @Override public void shutdown() { System.out.println("华为路由器关闭"); } @Override public void openWifi() { System.out.println("华为路由器打开wifi"); } @Override public void setting() { System.out.println("华为路由器设置"); } }
客户端
public class Client { public static void main(String[] args) { // MiFactory factory = new MiFactory(); // HWFactory factory = new HWFactory(); // IProductFactory factory = new HWFactory(); IProductFactory factory = new MiFactory(); IphoneProduct phoneProduct = factory.phoneProduct(); IRouterProduct routerProduct = factory.RouterProduct(); phoneProduct.sengMS(); phoneProduct.callup(); routerProduct.openWifi(); routerProduct.setting(); } }
package com.lee.demo01; public abstract class Builder { // 步骤 A abstract void builderA(); // 步骤 B abstract void builderB(); // 步骤 C abstract void builderC(); // 步骤 D abstract void builderD(); // 完工, 得到产品 abstract Product getProduct(); }
package com.lee.demo01; // 产品 public class Product { private String buildA; private String buildB; private String buildC; private String buildD; public String getBuildA() {return buildA;} public void setBuildA(String buildA) {this.buildA = buildA;} public String getBuildB() {return buildB;} public void setBuildB(String buildB) {this.buildB = buildB;} public String getBuildC() {return buildC;} public void setBuildC(String buildC) {this.buildC = buildC;} public String getBuildD() {return buildD; } public void setBuildD(String buildD) {this.buildD = buildD;} @Override public String toString() { return "Product{" + "buildA='" + buildA + '\'' + ", buildB='" + buildB + '\'' + ", buildC='" + buildC + '\'' + ", buildD='" + buildD + '\'' + '}'; } }
package com.lee.demo01; // 具体的建造者--工人 public class Worker extends Builder{ private Product product; public Worker() { product = new Product(); } @Override void builderA() { System.out.println("工人进行步骤A..."); product.setBuildA("步骤A完成..."); } @Override void builderB() { System.out.println("工人进行步骤B..."); product.setBuildB("步骤B完成..."); } @Override void builderC() { System.out.println("工人进行步骤C..."); product.setBuildC("步骤C完成..."); } @Override void builderD() { System.out.println("工人进行步骤D..."); product.setBuildD("步骤D完成..."); } @Override Product getProduct() { return product; } }
private Product product; public Worker() { product = new Product();}
// 指挥, 核心 负责指挥构建一个工程, 工程如何构建 public class Director { // 指挥工按顺序完工 public Product build(Builder builder) { builder.builderA(); builder.builderB(); builder.builderC(); builder.builderD(); return builder.getProduct(); } }
public class Test { public static void main(String[] args) { // 指挥 Director director =new Director(); // 指挥工人完成产品 Product build = director.build(new Worker()); System.out.println(build.toString()); } }
public abstract class Builder { // 汉堡 abstract Builder builderA(String msg); // 可乐 abstract Builder builderB(String msg); // 薯条 abstract Builder builderC(String msg); // 甜点 abstract Builder builderD(String msg); abstract Product getProduct(); }
public class Product { private String buildA = "汉堡"; private String buildB = "可乐"; private String buildC = "薯条"; private String buildD = "甜点"; public String getBuildA() { return buildA; } public void setBuildA(String buildA) { this.buildA = buildA; } public String getBuildB() { return buildB; } public void setBuildB(String buildB) { this.buildB = buildB; } public String getBuildC() { return buildC; } public void setBuildC(String buildC) { this.buildC = buildC; } public String getBuildD() { return buildD; } public void setBuildD(String buildD) { this.buildD = buildD; } @Override public String toString() { return "Product{" + "buildA='" + buildA + '\'' + ", buildB='" + buildB + '\'' + ", buildC='" + buildC + '\'' + ", buildD='" + buildD + '\'' + '}'; } }
// 具体的建造者 public class Worker extends Builder { private Product product; public Worker() { product = new Product(); } @Override Builder builderA(String msg) { product.setBuildA(msg); return this; } @Override Builder builderB(String msg) { product.setBuildB(msg); return this; } @Override Builder builderC(String msg) { product.setBuildC(msg); return this; } @Override Builder builderD(String msg) { product.setBuildD(msg); return this; } @Override Product getProduct() { return product; } }
private Product product; public Worker() { product = new Product();}
public class Test { public static void main(String[] args) { // 服务员 Worker worker = new Worker(); // Product product = worker.getProduct(); Product product = worker.builderA("全家桶").builderB("雪碧").getProduct(); System.out.println(product.toString()); } }
Product product = worker.builderA("全家桶").builderB("雪碧").getProduct();
- 优点:
- 产品的建造和表示分离,实现了解耦。使用建造者模式可以使客户端不必知道产品内部组成的细节
- 将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰
- 具体的建造者类之间是相互独立的,这有利于系统的扩展。增加新的具体建造者无需修改原有类库的代码,符合开闭原则
- 缺点:
- 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
- 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。
应用场景
建造者与抽象工厂模式的比较
package com.lee.demo01; import java.util.Date; /* 1. 实现一个接口 Cloneable 2. 重写一个方法 clone() 3. 无参构造、有参构造 4. getter setter */ public class Video implements Cloneable { private String name; private Date createTime; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } public Video() { } public Video(String name, Date createTime) { this.name = name; this.createTime = createTime; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } @Override public String toString() { return "Video{" + "name='" + name + '\'' + ", createTime=" + createTime + '}'; } }
package com.lee.demo01; import java.util.Date; public class Bili { public static void main(String[] args) throws CloneNotSupportedException { Date date = new Date(); Video video = new Video("Kite Study Java", date); System.out.println(video); System.out.println(video.hashCode()); // 浅克隆 Video video_c = (Video) video.clone(); System.out.println(video_c); System.out.println(video_c.hashCode()); System.out.println("=========="); date.setTime(220002020); System.out.println(video); System.out.println(video_c); System.out.println("=========="); date = new Date(); video.setCreateTime(date); System.out.println(video); System.out.println(video_c); } }
输出结果
Video{name='Kite Study Java', createTime=Tue Apr 26 20:17:50 CST 2022} 1735600054 Video{name='Kite Study Java', createTime=Tue Apr 26 20:17:50 CST 2022} 21685669 ========== Video{name='Kite Study Java', createTime=Sat Jan 03 21:06:42 CST 1970} Video{name='Kite Study Java', createTime=Sat Jan 03 21:06:42 CST 1970} ========== Video{name='Kite Study Java', createTime=Tue Apr 26 20:17:50 CST 2022} Video{name='Kite Study Java', createTime=Sat Jan 03 21:06:42 CST 1970}
package com.lee.demo02; import java.util.Date; public class Video implements Cloneable { private String name; private Date createTime; @Override protected Object clone() throws CloneNotSupportedException { Object obj = super.clone(); Video v = (Video) obj; v.createTime = (Date) this.createTime.clone(); return v; } public Video() { } public Video(String name, Date createTime) { this.name = name; this.createTime = createTime; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } @Override public String toString() { return "Video{" + "name='" + name + '\'' + ", createTime=" + createTime + '}'; } }
package com.lee.demo02; import java.util.Date; public class Bili { public static void main(String[] args) throws CloneNotSupportedException { Date date = new Date(); Video video = new Video("Kite Study Java", date); System.out.println(video); System.out.println(video.hashCode()); // 浅克隆 Video video_c = (Video) video.clone(); System.out.println(video_c); System.out.println(video_c.hashCode()); System.out.println("=========="); date.setTime(220002020); System.out.println(video); System.out.println(video_c); System.out.println("=========="); date = new Date(); video.setCreateTime(date); System.out.println(video); System.out.println(video_c); } }
输出结果
Video{name='Kite Study Java', createTime=Tue Apr 26 20:19:28 CST 2022} 1735600054 Video{name='Kite Study Java', createTime=Tue Apr 26 20:19:28 CST 2022} 21685669 ========== Video{name='Kite Study Java', createTime=Sat Jan 03 21:06:42 CST 1970} Video{name='Kite Study Java', createTime=Tue Apr 26 20:19:28 CST 2022} ========== Video{name='Kite Study Java', createTime=Tue Apr 26 20:19:28 CST 2022} Video{name='Kite Study Java', createTime=Tue Apr 26 20:19:28 CST 2022}
// 要被适配的类 public class Adaptee { public void request() { System.out.println("连接网线上网"); } }
// 接口转换器的抽象实现 public interface NetToUSB { // 作用:处理请求 public void handleRequest(); }
// 真正的适配器 public class Adapter extends Adaptee implements NetToUSB { @Override public void handleRequest() { super.request(); } }
public class Computer { public void net(NetToUSB adapter) { // 上网的具体实现 adapter.handleRequest(); } public static void main(String[] args) { // 电脑 Computer computer = new Computer(); // 网线 // Adaptee adaptee = new Adaptee(); // 转接器 Adapter adapter = new Adapter(); computer.net(adapter); } }
Adaptee adaptee = new Adaptee();
不需要显示出现,Adapter继承了Adaptee
// 要被适配的类 public class Adaptee { public void request() { System.out.println("连接网线上网"); } }
// 接口转换器的抽象实现 public interface NetToUSB { // 作用:处理请求 public void handleRequest(); }
// 热拔插式 public class Adapter implements NetToUSB{ private Adaptee adaptee; public Adapter(Adaptee adaptee) { this.adaptee = adaptee; } @Override public void handleRequest() { adaptee.request(); } }
public class Computer { public void net(NetToUSB adapter) { // 上网的具体实现 adapter.handleRequest(); } public static void main(String[] args) { // 电脑 Computer computer = new Computer(); // 网线 Adaptee adaptee = new Adaptee(); // 转接器 Adapter adapter = new Adapter(adaptee); computer.net((NetToUSB) adapter); } }
继承 (类适配器 单继承)
组合 (对象适配器 常用)
// 品牌 public interface Brand {void info();} // Apple public class Apple implements Brand { @Override public void info() { System.out.print("苹果"); } } // 联想 public class Lenovo implements Brand { @Override public void info() { System.out.print("联想"); } }
public abstract class Computer { // 组合 protected Brand brand; public Computer(Brand brand) { this.brand = brand; } public void info() { // 自带品牌 brand.info(); } } // Laptop public class Laptop extends Computer { public Laptop(Brand brand) { super(brand); } @Override public void info() { super.info(); System.out.println("笔记本"); } } // Desktop public class Desktop extends Computer { public Desktop(Brand brand) { super(brand); } @Override public void info() { super.info(); System.out.println("台式机"); } }
public class Test { public static void main(String[] args) { Computer computer = new Laptop(new Apple()); computer.info(); // 苹果笔记本 Computer computer2 = new Desktop(new Lenovo()); computer2.info(); // 联想台式机 } }
代理模式的优点
缺点
代码步骤
接口
// 租房 public interface Rent { public void rent(); }
真实角色
// 房东 public class Host implements Rent{ @Override public void rent() { System.out.println("房东要出租房子了"); } }
代理角色
// 代理 public class Proxy implements Rent { private Host host; public Proxy() { } public Proxy(Host host) { this.host = host; } @Override public void rent() { host.rent(); } // 看房 public void seeHouse() { System.out.println("中介带你看房"); } // 签合同 public void signContract() { System.out.println("签租赁合同"); } // 收中介费 public void fare() { System.out.println("收中介费"); } }
客户端访问代理角色
public class Client { public static void main(String[] args) { Host host = new Host(); // host.rent(); // 代理 Proxy proxy = new Proxy(host); proxy.rent(); proxy.fare(); proxy.seeHouse(); proxy.signContract(); } }
接口
package com.lee.demo02; public interface UserService { // 增删改查 public void add(); public void delete(); public void update(); public void query(); }
真实角色
public class UserServiceImpl implements UserService{ @Override public void add() { System.out.println("增加一个用户"); } @Override public void delete() { System.out.println("删除一个用户"); } @Override public void update() { System.out.println("修改一个用户"); } @Override public void query() { System.out.println("查询一个用户"); } }
代理
package com.lee.demo02; public class UserServiceProxy implements UserService{ private UserServiceImpl userService; public void setUserService(UserServiceImpl userService) { this.userService = userService; } @Override public void add() { log("add"); userService.add(); } @Override public void delete() { log("delete"); userService.delete(); } @Override public void update() { log("update"); userService.update(); } @Override public void query() { log("query"); userService.query(); } // 日志方法 public void log(String msg) { System.out.println("使用了" + msg + "方法"); } }
客户端访问
public class Client { public static void main(String[] args) { UserServiceImpl userService = new UserServiceImpl(); UserServiceProxy proxy = new UserServiceProxy(); proxy.setUserService(userService); proxy.add(); proxy.delete(); proxy.update(); proxy.query(); } }
需要了解两个类:
Proxy
:代理,InvocationHandler
:调用处理程序
优点
接口
// 租房 public interface Rent { public void rent(); }
真实角色
// 房东 public class Host implements Rent { @Override public void rent() { System.out.println("房东要出租房子了"); } }
动态代理
package com.lee.demo03; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; // 使用这个类自动生成代理类 public class ProxyInvocationHandler implements InvocationHandler { // 被代理的接口 private Rent rent; public void setRent(Rent rent) { this.rent = rent; } // 生成得到代理类 public Object getProxy() { return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this); } // 处理代理实例,并返回结果 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { seeHouse(); fare(); // 动态代理的本质就是使用反射机制实现的 return method.invoke(rent, args); } // 看房 public void seeHouse() { System.out.println("中介带你看房"); } // 签合同 public void signContract() { System.out.println("签租赁合同"); } // 收中介费 public void fare() { System.out.println("收中介费"); } }
客户端访问
public class Client { public static void main(String[] args) { // 真实角色 Host host = new Host(); // 代理角色 : 现在没有 ProxyInvocationHandler pih = new ProxyInvocationHandler(); // 通过调用程序处理角色来处理要调用的接口对象 pih.setRent(host); Rent proxy = (Rent) pih.getProxy(); proxy.rent(); } }
接口
public interface UserService { // 增删改查 public void add(); public void delete(); public void update(); public void query(); }
真实角色
public class UserServiceImpl implements UserService { @Override public void add() { System.out.println("增加一个用户"); } @Override public void delete() { System.out.println("删除一个用户"); } @Override public void update() { System.out.println("修改一个用户"); } @Override public void query() { System.out.println("查询一个用户"); } }
动态代理
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; // 使用这个类自动生成代理类 public class ProxyInvocationHandler implements InvocationHandler { // 被代理的接口 private Object target; public void setTarget(Object target) { this.target = target; } // 生成得到代理类 public Object getProxy() { return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } // 处理代理实例,并返回结果 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { log(method.getName()); // 动态代理的本质就是使用反射机制实现的 return method.invoke(target, args); } // 代理抽象出来的功能 public void log(String msg) { System.out.println("执行了" + msg + "方法"); } }
客户端访问
public class Client { public static void main(String[] args) { // 真实角色 UserServiceImpl userService = new UserServiceImpl(); // UserServiceImplTWO 如果实现了,也可以代理 // UserServiceImplTWO userService2 = new UserServiceImplTWO(); // 代理角色, 不存在 ProxyInvocationHandler pih = new ProxyInvocationHandler(); // 设置要代理的对象 pih.setTarget(userService); // 动态生成代理类 UserService proxy = (UserService) pih.getProxy(); proxy.add(); } }
其他参见菜鸟教程设计模式