设计模式都会遵循OOP原则,从而提高代码的效率。
OOP原则为下图:
单例模式
参考我的上一期博客:JAVA 单例模式详解_Ostkakah的博客-CSDN博客
工厂模式
工厂模式分为简单工厂模式和工厂方法模式。
简单工厂模式:只有一个工厂,这个工厂负责造所有的东西,用户只负责告诉工厂要造什么东西。
public class catFactory {
//简单工厂模式
public static car getCar(String name) {
if(name.equals("五菱宏光")){
return new wuling();
}else if(name.equals("特斯拉")){
return new tasla();
}else{
return null;
}
}
}
上述的伪代码中工厂通过判断语句来造东西,该模式的缺点是添加生产的东时需要修改工厂里的方法,不符合开闭原则,所以创建了工厂方法模式。
工厂方法模式: 每一个东西都有其对应的生产工厂,在获取想要的东西时只需要去调用对应的工厂方法,在添加新的物品时只要添加对应的工厂就可以了,正好符合开闭原则。
public static void main(String[] args) {
wlingFactory.getCar();//直接从工厂获取车
}
有读者可能会问:为什么不直接调用new来创建东西呢?因为作为用户我们只关心买东西,而不关心卖东西,如何创建一个东西时需要很多的参数,这时用户也很难知道全部的参数。另一个原因是因为给每个东西添加一个生产工厂可以大大减少耦合性。
抽象工厂模式
抽象工厂模式是提供了一个创建一系列相关或者相互依赖对象的接口,无需指定它们具体的类。
创建接口在该类中还会存在一个或多个接口,这些接口代表产品种类。从而产生了小米工厂和华为工厂。但在后续添加产品的时候需要在抽象工厂中添加产品的接口,不符合开闭原则。
建造者模式
定义: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
作用:在用户不知道对象的构造过程和细节的情况下就可以直接创建复杂的对象,经常用创建复杂的对象。
public abstract class Builder {
//创建工人模板
abstract void Builder1();//表示建造步骤1
abstract void Builder2();//2
abstract void Builder3();//3
abstract void Builder4();//4
abstract Product getProduct();//得到产品
}
public class Worker extends Builder {
//具体建造者:工人
private Product product;
public Worker() {
this.product = new Product();//工人创造产品
}
@Override
void Builder1() {
product.setBuild1("步骤1");
System.out.println("步骤1");
}
@Override
void Builder2() {
product.setBuild1("步骤2");
System.out.println("步骤2");
}
@Override
void Builder3() {
product.setBuild1("步骤3");
System.out.println("步骤3");
}
@Override
void Builder4() {
product.setBuild1("步骤4");
System.out.println("步骤4");
}
@Override
Product getProduct() {
return product;
}
}
package com.Builder;
//指挥:核心,负责指挥构建一个工程,工程如何构建由它决定
public class Directer {
//指挥工人按照顺序建房子
public Product build(Builder builder){
builder.Builder1();
builder.Builder2();
builder.Builder3();
builder.Builder4();
return builder.getProduct();
}
}
public class Product {
//产品: 房子
private String build1;
private String build2;
private String build3;
private String build4;
public void setBuild1(String build1) {
this.build1 = build1;
}
public void setBuild2(String build2) {
this.build2 = build2;
}
public void setBuild3(String build3) {
this.build3 = build3;
}
public void setBuild4(String build4) {
this.build4 = build4;
}
@Override
public String toString() {
return "Product{" +
"build1='" + build1 + '\'' +
", build2='" + build2 + '\'' +
", build3='" + build3 + '\'' +
", build4='" + build4 + '\'' +
'}';
}
}
public class text {
public static void main(String[] args) {
//创建指挥
//指挥者的存在很重要
Directer directer = new Directer();
//指挥工人完成产品
Product build = directer.build(new Worker());
System.out.println(build.toString());
}
}
用户就是指挥,用户不需要考虑工人如何完成工作,用户只负责告诉工人要做什么就可以了。
缺点:如果产品的内部变化复杂,可能会导致需要很多具体建造者来实现这种变化,导致系统变得很庞大。
抽象工厂模式和创建者模式的对比
可以将抽象工厂理解成"微观",创建者模式理解成"宏观"。
原型模式
原型模式本质上就ava中的克隆,克隆分为深克隆和浅克隆。浅克隆就类似创建一个快捷方式,当修改原实例对应的属性值时,克隆的实例也会被修改为新的值。
public class Video implements Cloneable{
private String name;
private Date createDate;
public Video(String name, Date createDate) {
this.name = name;
this.createDate = createDate;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
@Override
public String toString() {
return "Video{" +
"name='" + name + '\'' +
", createDate=" + createDate +
'}';
}
public static void main(String[] args) throws CloneNotSupportedException {
Video v1 = new Video("黄飞武", new Date());
Video v2 = (Video) v1.clone();
System.out.println(v1);
System.out.println(v2);
System.out.println("v1->hashCode :" + v1.hashCode());
System.out.println("v2->hashCode :" + v2.hashCode());
System.out.println(v2.getCreateDate());
System.out.println(v2.getName());
}
}
深克隆是克隆一个实例对应的新实例,这个实例不会因为原实例属性的修改而被修改。深克隆时就要依次克隆对应的属性。
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();
Video v = (Video) obj;
v.createDate = (Date) this.createDate.clone();
return obj;
}
适配器模式
定义:将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本的接口不兼容而不能一起工作的那些类可以一起工作了。
例子:轻薄本没有对应的网线接口,网线不能直接使用,可以通过一个适配器从而使它们可以一起使用。
桥接模式
代理模式
代理模式的优点:
1.可以使真实角色的操作更加纯粹,不用去关注以些公共的业务。
2.公共业务交给代理角色,实现了业务的分工。
3.公共业务发生扩展的时候方便集中管理。
代理模式的缺点:一个真实角色就会产生一个代理角色,代码两会翻倍,使得开发效率降低。(本质上就是在分层架构上多加一层,且符合开闭原则)
静态代理模式: 张三要租房子,他不认识房源所以他就会去找中介,通过中介去租房子,这个中介就是一个代理。赵六要出租房子,但是他不想去做出租房子这件事,所以他就会去请中介来代理这房子。这个中介就是代理。
//房东
public class Host implements Rent{
@Override
public void rent() {
System.out.println("租房");
}
}
//代理
public class proxy implements Rent{
private Host host;
@Override
public void rent() {
host.rent();
}
public proxy(Host host) {
this.host = host;
}
public proxy() {
}
public void seeHost(){
System.out.println("看房");
}
public void monrey(){
System.out.println("费用");
}
}
//客户
public class Client {
public static void main(String[] args) {
Host host = new Host();//房主要出租房子
proxy proxy = new proxy(host);//通过一个代理人,代理房子,但是呢,代理通常要使用会有附加操作
proxy.rent();
proxy.seeHost();
proxy.monrey();
}
}
动态代理:
1.动态代理和静态代理的角色一样。
2.动态代理的类是动态生成的,不是我们直接写好的。
3.动态代理分为两大类:
基于接口:JDK动态代理。
基于类:cglib。
动态代理的例子为下:
//动态代理
public class proxyinvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理的本质就是使用反射机制实现
//此方法为激活方法,会在使用代理的时候自动调用该方法
return method.invoke(rent, args);
}
//代理类的接口 target
private Object target;
public void setTarget(Object target) {//设置要代理的接口实现类
this.target = target;
}
//生成得到的代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(),this);//本类的加载器,代理的接口,InvocationHandler
}
}
class Test {
public static void main(String[] args) {
//真实角色
Host2 host = new Host2();//房主
//代理角色
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//通过调用程序处理角色来处理我们要调用的接口对象
pih.setTarget(host);
Rent2 pro = (Rent2) pih.getProxy();
pro.rent();
}
}
//房东
class Host2 implements Target {
@Override
public void Target() {
System.out.println("租房");
}
}
//租房
public interface Target {
void Target();
}
//测试类
class Test {
public static void main(String[] args) {
//真实角色
Host2 host = new Host2();//房主
//代理角色
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//通过调用程序处理角色来处理我们要调用的接口对象
pih.setTarget(host);
Rent2 pro = (Rent2) pih.getProxy();//这里的代理类是自动生成的。
pro.Target();
}
}
动态代理基于: Proxy类和InvocationHandler类。
动态代理的优点:
1.一个动态代理类代理的是一个接口,一般就是对应的一类业务。
2.一个动态代理类可以代理多个类,只要是实现了同一个接口即可。(例子:万能target)