Java实现23种设计模式教程(作者原创)
个人简介
作者是一个来自河源的大三在校生,以下笔记都是作者自学之路的一些浅薄经验,如有错误请指正,将来会不断的完善笔记,帮助更多的Java爱好者入门。
文章目录
- 个人简介
- Java设计模式
- 单例模式
- 饿汉式
- 饿汉式在JDK中的Runtime类运用
- 懒汉式(不加锁,不安全)
- 测试懒汉式不加锁的线程不安全性
- 懒汉式(加锁,安全)
- 测试安全性
- 利用静态内部类
- 利用枚举(不太懂)
- 原型模式(多例)
- 浅拷贝
- 深拷贝
- 工厂模式
- 简单工厂模式(推荐使用)
- 简单工厂模式弊端
- 工厂方法模式(拆分简单工厂)
- 抽象工厂模式(很大的工厂)
- 建造者模式
- 代理模式
- 静态代理
- 动态代理(JDK动态代理)
- 装饰器模式
- 适配器模式
- 类适配器
- 对象适配器
- 接口适配器
- 享元模式
- 多线程环境下的问题
- 组合模式(树型结构)
- 外观模式
- **传统方式(买水果问题):**
- 外观模式(买水果问题):
- 桥接模式
- 观察者模式
- 备忘录模式
- 责任链模式
- 策略模式
- 模板模式
Java设计模式
单例模式
单例模式步骤:
1.构造器私有
2.创建对象(比如饿汉式就是先new,懒汉式就是判断为null再new)
3.返回实例对象(都是一样)
饿汉式
所谓的饿汉式,也就是提前new好对象,再提供一个方法,返回这个new好的对象实例。还有要把构造器私有化,通过方法new对象,控制到只有一个实例对象
饿汉式缺点:虽然是线程安全,但是会浪费资源,因为我们的饿汉式是一开始就new对象,如果没有人使用到这个对象,那就是一种资源的浪费,所以下面我们要讲懒汉式,懒汉式线程不安全,但是不会造成资源浪费,因为只有用到了才会new对象
代码实现:
1:实体类只需要正常写:
public class person {private String id;private String name;private int age;public person() {}public person(String id, String name, int age) {this.id = id;this.name = name;this.age = age;}
2:单例类:
public class hungry {/*** 单例模式-饿汉式*///1.创建static final对象private static final person person=new person();//2.构造器私有,为了让人只能用类去调用getInstance方法获取实例,而不能new这个单例的对象private hungry(){}//3.返回对象public static person getInstance(){return person;}}
3.测试:
public static void main(String[] args) {//测试单例person p1 = hungry.getInstance();person p2 = hungry.getInstance();//hashcode相同证明是同一个对象System.out.println("p1.hashCode:"+p1.hashCode());System.out.println("p2.hashCode:"+p2.hashCode());System.out.println("p1==p2:"+(p1==p2));}
4.结果:
p1.hashCode:1690716179
p2.hashCode:1690716179
p1==p2:true
饿汉式在JDK中的Runtime类运用
查看Runtime源码:
public class Runtime {private static final Runtime currentRuntime = new Runtime();private static Version version;/*** Returns the runtime object associated with the current Java application.* Most of the methods of class {@code Runtime} are instance* methods and must be invoked with respect to the current runtime object.** @return the {@code Runtime} object associated with the current* Java application.*/public static Runtime getRuntime() {return currentRuntime;}/** Don't let anyone else instantiate this class */private Runtime() {}
这就是一种标准的单例模式-饿汉式
懒汉式(不加锁,不安全)
懒汉式是线程不安全的,但是他具有懒加载机制,也就是用到才new对象,这样不会造成资源的浪费
public class lazyNotSync {/*** 单例模式-懒汉式(不加锁) 线程不安全*///1.首先,单例模式要把构造器私有private lazyNotSync(){}//2.懒汉式的对象置为nullprivate static person person=null;//3.返回实例public static person getInstance(){if(person==null){person=new person(); //这个new对象并赋值不是原子操作,所以在多线程是不安全的return person;}else {return person;}}}
测试懒汉式不加锁的线程不安全性
class lazyNotSyncMain{public static void main(String[] args) throws InterruptedException {//这里不能用ArrayList,因为ArrayList是线程不安全的,所以在多线程的add,会导致少添加的情况CopyOnWriteArrayList<Object> list = new CopyOnWriteArrayList<>();for (int i = 0; i < 5; i++) {new Thread(new Runnable() {@Overridepublic void run() {list.add(lazyNotSync.getInstance());}}).start();}Thread.sleep(100);for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i).hashCode());}}
}
结果hashcode不一致,说明不是一个对象:
1929600551
1690716179
1053782781
1211888640
564160838
懒汉式(加锁,安全)
public class lazySync {/*** 单例模式-懒汉式,加锁,保证线程安全,但是呢,加了锁之后性能会下降**///1.构造器私有private lazySync(){}//2.创建对象private static person person=null;private static final Object lock=new Object();//3.返回实例public static person getInstance(){synchronized (lock){if(person==null){person=new person();return person;} else {return person;}}}}
测试安全性
class lazySyncMain{public static void main(String[] args) {for (int i = 0; i < 10; i++) {new Thread(()->{System.out.println(lazySync.getInstance().hashCode());}).start();}}}
结果:
1226907195
1226907195
1226907195
1226907195
1226907195
1226907195
1226907195
1226907195
1226907195
1226907195
利用静态内部类
public class staticClass {/*** 利用静态内部类的特性来实现单例模式(推荐)* 优点:线程安全,懒加载(节省资源)* 可以说是饿汉式和懒汉式更好的一种* =====* 写法类似于饿汉式。。只是把new对象放到一个私有的静态内部类中** =====* 静态内部类的特性:* 当classloader时静态内部类不会随着加载,当我们去调用时才会加载(懒加载)*///1.构造器私有private staticClass(){}//如果这段代码不放到静态内部类中,它将随着类加载而new对象(占资源)
// private static final person person=new person();//2.创建对象(只不过是在静态内部类中创建对象)private static class personStatic{private static final person person=new person();}//3.返回对象public static person getInstance(){return personStatic.person;}}
测试:
class staticClassMain{public static void main(String[] args) {for (int i = 0; i < 5; i++) {new Thread(new Runnable() {@Overridepublic void run() {System.out.println(staticClass.getInstance().hashCode());}}).start();}}
}
利用枚举(不太懂)
原型模式(多例)
原型模式其实就是复制的意思,包含着深拷贝和浅拷贝。浅拷贝复制的引用数据类型变量只是地址,深拷贝则是内容
实现原型模式的实体类要实现Cloneable接口
注意:实现了Cloneable的类才能拷贝(克隆)
浅拷贝
public class person implements Cloneable {private String id;private String name;private int age;private Firend firend; //朋友 ---模拟深拷贝和浅拷贝public person() {}public person(String id, String name, int age, Firend firend) {this.id = id;this.name = name;this.age = age;this.firend = firend;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Firend getFirend() {return firend;}public void setFirend(Firend firend) {this.firend = firend;}@Overridepublic String toString() {return "person{" +"id='" + id + '\'' +", name='" + name + '\'' +", age=" + age +", firend=" + firend +'}';}//浅拷贝@Overrideprotected person clone() throws CloneNotSupportedException {person person = (person) super.clone(); //克隆对象return person;}}
public class Firend {private String id;private String name;public Firend() {}public Firend(String id, String name) {this.id = id;this.name = name;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Firend{" +"id='" + id + '\'' +", name='" + name + '\'' +'}';}
}
public class prototypeMain {public static void main(String[] args) throws CloneNotSupportedException {person person = new person("001","张三",18,new Firend("999","小明同学"));person p1 = person.clone();System.out.println("person是否=p1:"+(person==p1)); //false ,说明克隆出来的对象不是同一个对象System.out.println("person:"+person);System.out.println("p1:"+p1);//说明我们的firend是浅拷贝System.out.println("person.getFirend().hashCode()==p1.getFirend().hashCode():"+(person.getFirend().hashCode()==p1.getFirend().hashCode()));}
结果:
person是否=p1:false
person:person{id='001', name='张三', age=18, firend=Firend{id='999', name='小明同学'}}
p1:person{id='001', name='张三', age=18, firend=Firend{id='999', name='小明同学'}}
person.getFirend().hashCode()==p1.getFirend().hashCode():true
深拷贝
深拷贝有多种方法,这里我们只使用一种,也是最简单的一种
person和Firend都要实现Cloneable和重写clone方法。。。。。。。。。。。。。才能实现深拷贝
public class person implements Cloneable {private String id;private String name;private int age;private Firend firend; //朋友 ---模拟深拷贝和浅拷贝public person() {}public person(String id, String name, int age, Firend firend) {this.id = id;this.name = name;this.age = age;this.firend = firend;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Firend getFirend() {return firend;}public void setFirend(Firend firend) {this.firend = firend;}@Overridepublic String toString() {return "person{" +"id='" + id + '\'' +", name='" + name + '\'' +", age=" + age +", firend=" + firend +'}';}//深拷贝@Overrideprotected person clone() throws CloneNotSupportedException {person person = (person) super.clone(); //克隆对象//Firend也要实现Cloneable和clone方法//深拷贝:把引用数据类型变量单独的克隆并复制到person.firendperson.firend=firend.clone();return person;}}
public class Firend implements Cloneable {private String id;private String name;public Firend() {}public Firend(String id, String name) {this.id = id;this.name = name;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overrideprotected Firend clone() throws CloneNotSupportedException {Firend firend = (Firend) super.clone();return firend;}@Overridepublic String toString() {return "Firend{" +"id='" + id + '\'' +", name='" + name + '\'' +'}';}
}
public class prototypeMain {public static void main(String[] args) throws CloneNotSupportedException {person person = new person("001","张三",18,new Firend("999","小明同学"));person p1 = person.clone();System.out.println("person是否=p1:"+(person==p1)); //false ,说明克隆出来的对象不是同一个对象System.out.println("person:"+person);System.out.println("p1:"+p1);//说明我们的firend是深拷贝System.out.println("person.getFirend().hashCode()==p1.getFirend().hashCode():"+(person.getFirend().hashCode()==p1.getFirend().hashCode()));}
}
结果:
person是否=p1:false
person:person{id='001', name='张三', age=18, firend=Firend{id='999', name='小明同学'}}
p1:person{id='001', name='张三', age=18, firend=Firend{id='999', name='小明同学'}}
person.getFirend().hashCode()==p1.getFirend().hashCode():false
工厂模式
工厂模式分为简单工厂和工厂方法,工厂模式和抽象工厂模式不是一个概念
总结:工厂模式只是生产同一类产品(比如手机工厂生产手机对象,电脑工厂生产电脑对象)
简单工厂模式(推荐使用)
总结:主要依靠if elseif 在一个大的工厂类中根据不同的传参来new不同的对象,这个大的工厂必须要是一个品类,比如手机工厂和电脑工厂要分开,后面的抽象工厂模式才能通过一个品牌分类,这里简单工厂和工厂方法只能一个种类的工厂(但是可以写多个工厂类)
实体类要提供一个类型的接口,工厂模式返回对象需要多态,所以要有接口或者父类
public interface phone {//使用接口来实现多态写法String getPhoneName();}
public class iphone implements phone {/*** 苹果手机*/private String id;private String name;private double price;public iphone() {}public iphone(String id, String name, double price) {this.id = id;this.name = name;this.price = price;}public void setId(String id) {this.id = id;}public void setName(String name) {this.name = name;}public void setPrice(double price) {this.price = price;}@Overridepublic String toString() {return "iphone{" +"id='" + id + '\'' +", name='" + name + '\'' +", price=" + price +'}';}@Overridepublic String getPhoneName() {return this.name;}
}
public class xiaomiPhone implements phone {/*** 小米手机*/private String id;private String name;private double price;public xiaomiPhone() {}public xiaomiPhone(String id, String name, double price) {this.id = id;this.name = name;this.price = price;}public void setId(String id) {this.id = id;}public void setName(String name) {this.name = name;}public void setPrice(double price) {this.price = price;}@Overridepublic String toString() {return "xiaomiPhone{" +"id='" + id + '\'' +", name='" + name + '\'' +", price=" + price +'}';}@Overridepublic String getPhoneName() {return this.name;}
}
简单工厂(核心代码实现)
public class phoneFactory {/*** 简单工厂模式* 缺点:不满足设计模式原则-开闭原则(对扩展性开,对修改关闭)*///简单工厂根据传参去判断new哪个对象,因为这里要使用多态写法,所以下面要定义一个接口,哪怕空接口都行,extends也行public static phone getPhone(String name){if(name==null||name.equals(""))return null;if(name.equals("小米"))return new xiaomiPhone("mi-001","小米11",4999.0);else if(name.equals("苹果"))return new iphone("iphone-888","iPhone12 Pro max",10999.0);return null;}}
测试
class phoneFactoryMain{public static void main(String[] args) {//通过工厂就可以获得对象phone p1 = phoneFactory.getPhone("");phone p2 = phoneFactory.getPhone("小米");phone p3 = phoneFactory.getPhone("苹果");System.out.println(p1);System.out.println(p2.getPhoneName());System.out.println(p3.getPhoneName());}}
null
小米11
iPhone12 Pro max
简单工厂模式弊端
试想,当我们需要添加一款手机的时候,我们需要在工厂类的if else 里面添加new新手机的代码,这样就违反了设计模式的开闭原则了,这时候我们如果很介意这个开闭原则的话,可以使用工厂方法模式
工厂方法模式(拆分简单工厂)
总结:工厂方法也就是为了解决简单工厂不满足设计模式原则中的开闭原则,工厂方法不采用简单工厂那种在一个大工厂(单一类型,比如手机工厂、电脑工厂要分开不同的工厂)中通过if elseif 根据不同的传参来new不同的对象了,而是把这个大的工厂拆分。拆分成一个工厂接口,
简单工厂是一个大的综合一个类型的工厂,而工厂方法模式是各自品牌类型的东西单独建立一个工厂,这样更符合我们日常生活的情况,比如手机里面有小米手机、苹果手机,这样工厂又会拆分成小米手机工厂、苹果手机工厂
public abstract class factory {/*** 这个工厂是生产手机,所以我们要提供一个抽象方法来生产手机*///抽象类的获取手机方法,一定不能指定获取什么手机,要用多态。abstract phone getPhoneByFactory();}
苹果手机工厂
public class iPhoneFactory extends factory {/*** 苹果手机工厂*/@Overridephone getPhoneByFactory() {return new iphone("iphone-888","iPhone12 Pro max",10999.0);}}
小米手机工厂
public class xiaomiFactory extends factory{/*** 小米手机工厂*/@Overridephone getPhoneByFactory() {return new xiaomiPhone("mi-001","小米11",4999.0);}
}
苹果手机实体类
public class iphone implements phone {/*** 苹果手机*/private String id;private String name;private double price;public iphone() {}public iphone(String id, String name, double price) {this.id = id;this.name = name;this.price = price;}public void setId(String id) {this.id = id;}public void setName(String name) {this.name = name;}public void setPrice(double price) {this.price = price;}@Overridepublic String toString() {return "iphone{" +"id='" + id + '\'' +", name='" + name + '\'' +", price=" + price +'}';}
}
小米手机实体类
public class xiaomiPhone implements phone{//小米手机private String id;private String name;private double price;public xiaomiPhone() {}public xiaomiPhone(String id, String name, double price) {this.id = id;this.name = name;this.price = price;}public void setId(String id) {this.id = id;}public void setName(String name) {this.name = name;}public void setPrice(double price) {this.price = price;}@Overridepublic String toString() {return "xiaomiPhone{" +"id='" + id + '\'' +", name='" + name + '\'' +", price=" + price +'}';}}
手机接口:
public interface phone {}
利用各自的手机工厂创建手机对象
public class factoryMethodMain {public static void main(String[] args) {factory xiaomiFactory = new xiaomiFactory();factory iPhoneFactory = new iPhoneFactory();System.out.println(xiaomiFactory.getPhoneByFactory());System.out.println(iPhoneFactory.getPhoneByFactory());}}
抽象工厂模式(很大的工厂)
总结:抽象工厂模式是生产一个品牌的任何产品(比如某一个抽象工厂,小米工厂去实现它,那么小米工厂就是抽象工厂的子类,也就是说小米工厂可以小米品牌下的所有商品,也就是说这个小米工厂可以生产小米手机、小米笔记本、小米电脑、小米耳机等等。。。),而工厂模式不可以,工厂模式只能生产同一类产品,比如就生产笔记本,但是。如果抽象工厂定义的生产产品只有一类品牌产品,那么这个抽象工厂模式就和工厂模式没有区别了。(当且仅当抽象工厂只有一个抽象方法时)
需求:小米公司和华为公司要生产手机和电脑。
定义抽象工厂:
public abstract class abstractFactory {/*** 抽象工厂模式的抽象工厂:生产手机和电脑* 如果是工厂方法模式的抽象工厂:只能生产手机或者只生产电脑*/public abstract phone getPhone(); //生产手机public abstract computer getComputer(); //生产电脑}
定义华为品牌的工厂(生产多个类型产品)
public class huaweiFactory extends abstractFactory {@Overridepublic phone getPhone() {return new huaweiPhone("h-05","华为Mate40 pro",5388.0);}@Overridepublic computer getComputer() {return new huaweiComputer("h-33","华为笔记本电脑",5800.0);}}
定义小米品牌的工厂(生产多个类型产品)
public class xiaomiFactory extends abstractFactory {@Overridepublic phone getPhone() {return new xiaomiPhone("x-01","小米11",3999.0);}@Overridepublic computer getComputer() {return new xiaomiComputer("x-22","小米笔记本电脑",5213.0);}}
手机接口:
public interface phone {}
电脑接口:
public interface computer {}
实体类:
public class xiaomiPhone implements phone {/*** 小米手机*/private String id;private String name;private double price;public xiaomiPhone() {}public xiaomiPhone(String id, String name, double price) {this.id = id;this.name = name;this.price = price;}
public class huaweiComputer implements computer {private String id;private String name;private double price;public huaweiComputer() {}public huaweiComputer(String id, String name, double price) {this.id = id;this.name = name;this.price = price;}
测试类:
public class abstractFactoryMain {/*** 抽象工厂模式*/public static void main(String[] args) {//创建小米的大工厂xiaomiFactory xiaomiFactory = new xiaomiFactory();//创建华为的大工厂huaweiFactory huaweiFactory = new huaweiFactory();//从小米的大工厂中生产小米手机和小米笔记本phone xiaomiPhone = xiaomiFactory.getPhone();computer xiaomComputer = xiaomiFactory.getComputer();System.out.println(xiaomiPhone);System.out.println(xiaomComputer);//从华为的大工厂中生产华为手机和华为笔记本System.out.println("=======================");phone huaweiPhone = huaweiFactory.getPhone();computer huaweiComputer = huaweiFactory.getComputer();System.out.println(huaweiPhone);System.out.println(huaweiComputer);}}
建造者模式
用于创建复杂对象,比如构造方法多变的情况下使用建造者模式很好用
建造者所需角色:抽象建造者、具体建造者、指挥者(非必要,可有可无:用于拼装建造的顺序)、测试
比如有一个项目:我们要建造一台电脑,里面有cpu、显卡、内存条、键盘等等。。(使用建造者模式实现这个项目)
抽象建造者:
public abstract class builder {//抽象建造者提供建造对象所需要的方法/*实现链式编程,addCPU等方法要返回一个builder对象*/public abstract builder addCPU(String cpu); //添加CPUpublic abstract builder addXianka(String xianka); //添加显卡public abstract builder addShubiao(String shubiao); //添加鼠标public abstract builder addKeyboard(String keyboard);//添加键盘public abstract builder addMemory(String memory); //添加内存条public abstract computer builderComputer(); //返回构建的computer对象}
具体建造者:
public class computerBuilder extends builder {private computer computer=new computer();//给电脑默认属性public computerBuilder(){computer.setCpu("i3");computer.setKeyboard("联想键盘");computer.setMemory("金士顿8g内存");computer.setShubiao("华硕鼠标");computer.setXianka("GTX1060");}@Overridepublic builder addCPU(String cpu) {computer.setCpu(cpu);return this; //返回当前调用者的对象,实现链式编程}@Overridepublic builder addXianka(String xianka) {computer.setXianka(xianka);return this;}@Overridepublic builder addShubiao(String shubiao) {computer.setShubiao(shubiao);return this;}@Overridepublic builder addKeyboard(String keyboard) {computer.setKeyboard(keyboard);return this;}@Overridepublic builder addMemory(String memory) {computer.setMemory(memory);return this;}@Overridepublic computer builderComputer() {return computer;}}
public class computer {private String cpu;private String xianka;private String shubiao;private String keyboard;private String memory; //内存public computer() {}public computer(String cpu, String xianka, String shubiao, String keyboard, String memory) {this.cpu = cpu;this.xianka = xianka;this.shubiao = shubiao;this.keyboard = keyboard;this.memory = memory;}public String getCpu() {return cpu;}public void setCpu(String cpu) {this.cpu = cpu;}public String getXianka() {return xianka;}public void setXianka(String xianka) {this.xianka = xianka;}public String getShubiao() {return shubiao;}public void setShubiao(String shubiao) {this.shubiao = shubiao;}public String getKeyboard() {return keyboard;}public void setKeyboard(String keyboard) {this.keyboard = keyboard;}public String getMemory() {return memory;}public void setMemory(String memory) {this.memory = memory;}@Overridepublic String toString() {return "computer{" +"cpu='" + cpu + '\'' +", xianka='" + xianka + '\'' +", shubiao='" + shubiao + '\'' +", keyboard='" + keyboard + '\'' +", memory='" + memory + '\'' +'}';}
}
director(可写可不写):也可以直接操作具体建造者,下面会有用director和不用director的写法:
public class director {/*** 指挥者。用来拼装具体建造者实现的方法*/private builder builder;// 私有化构造器,也可以不这么写private director(){}public director(builder builder){this.builder=builder;}//拼装方法public computer builder(){builder.addCPU("director_cpu");builder.addXianka("director_xianka");return builder.builderComputer();}}
Main测试:
public class builderMain {public static void main(String[] args) {System.out.println("不采用director类"); //不采用director类builder builder=new computerBuilder();computer computer = builder.builderComputer();System.out.println(computer);computer computer1 = builder.addCPU("i5").addXianka("RTX2080").builderComputer();System.out.println(computer1);computer computer2 = builder.addCPU("i7").addXianka("RTX2090").addMemory("金士顿32g").addShubiao("华为鼠标").builderComputer();System.out.println(computer2);System.out.println("=============");System.out.println("采用director类"); //采用director类director director = new director(new computerBuilder());computer builder1 = director.builder();System.out.println(builder1);}}
代理模式
静态代理
被代理的类
public class logger implements Mylogger {/*** 静态代理:* 当我们有个接口的实现类,其中需要对实现类的方法进行增强而不修改源代码,我们可以用代理模式* 需求:我们想不改变源代码的情况下对下面 System.out.println("写入日志。");的前面和后面加入一个输出语句** 实现:我们只需要创建一个logger的代理类,并实现Mylogger接口,重写方法即可*/@Overridepublic void writerLog() {System.out.println("写入日志。");}}
接口:
public interface Mylogger {public void writerLog();}
代理类:
public class proxyLogger implements Mylogger {private Mylogger mylogger;public proxyLogger(Mylogger logger){this.mylogger=logger;}@Overridepublic void writerLog() { //增强的方法System.out.println("logger被代理了===前");mylogger.writerLog(); //需要增强的方法System.out.println("logger被代理了===后");}
}
测试:
public class staticProxyMain {public static void main(String[] args) {proxyLogger proxyLogger = new proxyLogger(new logger());proxyLogger.writerLog();}}
结果:
logger被代理了===前
写入日志。
logger被代理了===后
动态代理(JDK动态代理)
要实现如上的结果,我们这次不用静态代理,而是用JDK动态代理
其实所谓的动态代理,也就是不用写代理类了,而是又JDK底层通过反射在内存中帮你创建好了一个代理类
public class logger implements loggers {/*** JDK动态代理:* 我们无需创建代理类,而是有JDK底层的反射帮我们在内存中自动创建*/@Overridepublic void writerlogger() {System.out.println("写入日志。。");}
}
public interface loggers {void writerlogger();}
动态代理:
public class loggerProxyMain {private static logger logger=new logger();public static void main(String[] args) {/*** public static Object newProxyInstance(ClassLoader loader,* Class<?>[] interfaces,* InvocationHandler h)*/loggers loggers= (com.design.proxy.dongtaiProxy.loggers) Proxy.newProxyInstance(logger.class.getClassLoader(), logger.class.getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {/*第一个参数:被代理的类的对象第二个参数:方法参数args*/System.out.println("代理开始====");//如果用代理实例调用方法,将会在这里执行Object invoke = method.invoke(logger, args);//不返回这个对象的话,代理实例为nullSystem.out.println("代理结束");return invoke; //返回代理实例,并返回到loggers对象中}});//****注意:进入invoke方法是有前提的,就是我们要使用代理实例对象loggers,如果不使用它就不会进入到invoke方法中//输入logger对象也行,也可以让他进入invoke方法
// System.out.println(loggers);/*当我们去调用代理的方法时,method.invoke就会监听到,并执行被代理的方法*/loggers.writerlogger();}}
装饰器模式
我们可以把装饰器分为主菜和配菜,配菜就是装饰器,而主菜就是被装饰的
公式:创建一个抽象类(作为被装饰者的父类),被装饰者类去继承它,然后创建装饰者抽象类并继承被装饰者的父类,再有装饰者子类去继承装饰者抽象类。
案例:
被装饰者的抽象类,在这里是最高的类
public abstract class breakFast {public abstract int cost(); //价格}
被装饰者具体类
public class rice extends breakFast {/*** 主食:米饭*/@Overridepublic int cost() {return 5;}}
public class noodles extends breakFast {/***主食: 面条*/@Overridepublic int cost() {return 10;}}
装饰者抽象类:继承与被装饰者的父类
public abstract class decorations extends breakFast{public abstract int cost(); //装饰者的钱}
装饰者类
public class coke extends decorations {private breakFast breakFast;private final int COKE_COST=2; //coke的价格public coke(breakFast breakFast){this.breakFast=breakFast;}@Overridepublic int cost() {return breakFast.cost()+COKE_COST;}
}
public class milk extends decorations {private breakFast breakFast;private final int MILK_COST=3; //milk的价格public milk(breakFast breakFast){this.breakFast=breakFast;}@Overridepublic int cost() {return breakFast.cost()+MILK_COST;}}
测试:
public class main {public static void main(String[] args) {rice rice = new rice(); //创建被装饰者对象milk milk = new milk(rice);//把被装饰者对象放到装饰者的构造方法上去System.out.println("rice:"+rice.cost());System.out.println("milk+rice:"+milk.cost());milk milk1 = new milk(milk);System.out.println("milk*2+rice"+milk1.cost());}}
适配器模式
适配器模式:就是把原本互不兼容的两样东西或者格式,转换成可以兼容
比如说:家用电压是220v,但是我们手机充电不需要这么大的电压,我们这时候需要电源适配器(充电头),去适配这个电压,把220v适配成(比如:5v,11v等等)
再比如说:有一个方法只能接收int类型数据,但是我们接收到了一个String类型数据,int和String本身就是两个不相同的类型,所以说这个方法是接收不到String类型的,我们可以使用适配器,把String类型转换(适配)成int类型,这样这个方法就可以接收到这个String类型数据了。
类适配器
公式:适配器类要继承src(原来的类),并实现dest(目标)接口
首先创建适配器类,并运用上面的公式:
public class classAdapter extends srcClass implements destInterface{/*** 类适配器是有公式的* 公式:类适配器要继承源类,实现于目标接口* public class classAdapter extends srcClass implements destInterface** srcClass:在这里是指家用电压220V* destInterface : 在这里是指我们想适配成多少v的电压,比如手机常用的电压 5v*/@Overridepublic int vivoBattery_5V() {int src = super.getSrc();int dest=src/44;return dest;}}
源(src)类:
public class srcClass {private final int v=220; //家用电压//源类生成220vpublic int getSrc(){return v;}}
目标接口:
public interface destInterface {int vivoBattery_5V(); //vivo手机想要多少伏的电压}
测试:
public class Test {public static void main(String[] args) {classAdapter classAdapter = new classAdapter();int res = classAdapter.vivoBattery_5V();System.out.println("当前电压:"+res+"v");}}
对象适配器
为什么会有对象适配器:我们的对象适配器都是在类适配器上优化的,类适配器的缺点是extends(继承),因为Java是单继承的,而我们的对象适配器不过就是把这个extends srcClass 优化成一个对象,通过构造器进行传入,然后通过这个对象进行调用srcClass的方法,而类适配器就是通过super关键字去调用方法。。
public class adapter implements destInterface {private srcClass srcClass; //把之前的类适配器的extends 源类,改成一个对象进行调用public adapter(srcClass srcClass){ //再通过构造器传入srcClass对象this.srcClass=srcClass;}@Overridepublic int get10V() {int src = srcClass.getV();int dest=src/22;return dest;}
}
public interface destInterface {int get10V();}
public class srcClass {private final int v=220;public int getV(){return v;}}
public class Test {public static void main(String[] args) {adapter adapter = new adapter(new srcClass());int v = adapter.get10V();System.out.println(v);}}
接口适配器
为何有接口适配器:我们上面说的两种适配器方式都有一个缺点:就是我们上面两种适配器都需要实现目标接口,当目标接口有多个适配方法时,我们都要对它进行实现,而我们不需要全部实现,只需要实现其中一个即可,我们的接口适配器就是为了解决这个问题的。
没有给接口方法默认实现时:
public interface dest {int adapter_5v();int adapter_10v();int adapter_20v();}
public class adapter implements dest {@Overridepublic int adapter_5v() {return 0;}@Overridepublic int adapter_10v() {return 0;}@Overridepublic int adapter_20v() {return 0;}
}
就需要全部进行实现,很复杂
public class srcClass {private final int v=220; //家用电压//源类生成220vpublic int getSrc(){return v;}}
public interface dest {/*** 当接口适配的方法很多,但是我们不需要全部的进行实现,我们可以随便给他一个默认值,用default修饰* 当我们需要具体实现某个方法时,只需要重写对应的方法即可*/default int adapter_5v(){return 0;}default int adapter_10v(){return 0;}default int adapter_20v(){return 0;}}
public class adapter implements dest {private srcClass srcClass;public adapter(srcClass srcClass){this.srcClass=srcClass;}@Overridepublic int adapter_10v() {int src = srcClass.getSrc();int res=src/22;return res;}}
class main{public static void main(String[] args) {adapter adapter = new adapter(new srcClass());int i = adapter.adapter_10v();System.out.println(i);}}
享元模式
享元模式:“享”是共享 ,“元”是对象 ,享元模式也就是一种利用共享技术对实例对象进行共享,提高实例对象的复用性,和节省资源的开销,减少对象的创建,应用在大量的“”相似“”对象,但是这些对象只有一些不同,我们可以用这个模式。
享元模式如何在定制相似的对象(对对象的数据进行修改):我们可以通过享元模式的简单工厂从HashMap/HashTable中get到,然后再用set方法对它进行定制。
何为相似的对象: 说白了也就是同一个类创建出来的对象就是相似的对象
案例:用户的网站界面属性(网站类型(type)、颜色(color),动态消息(message))
public abstract class website {/*** 总的网站抽象类*/public abstract void setColor(String color);public abstract void setMessages(List<String> messages);public abstract void setRandomCode(String randomCode);}
public class sina extends website {/*** 新浪网站*/private final String type="新浪";private String color;private List<String> messages;private String randomCode; //随机码public sina() {}public String getType() {return type;}public String getColor() {return color;}public List<String> getMessages() {return messages;}public String getRandomCode() {return randomCode;}@Overridepublic String toString() {return "sina{" +"type='" + type + '\'' +", color='" + color + '\'' +", messages=" + messages +", randomCode='" + randomCode + '\'' +'}';}@Overridepublic void setColor(String color) {this.color=color;}@Overridepublic void setMessages(List<String> messages) {this.messages=messages;}@Overridepublic void setRandomCode(String randomCode) {this.randomCode=randomCode;}
}
public class zhihu extends website {/*** 知乎*/private final String type="知乎";private String color;private List<String> messages;private String randomCode;public zhihu() {}public String getType() {return type;}public String getColor() {return color;}public List<String> getMessages() {return messages;}public String getRandomCode() {return randomCode;}@Overridepublic String toString() {return "zhihu{" +"type='" + type + '\'' +", color='" + color + '\'' +", messages=" + messages +", randomCode='" + randomCode + '\'' +'}';}@Overridepublic void setColor(String color) {this.color=color;}@Overridepublic void setMessages(List<String> messages) {this.messages=messages;}@Overridepublic void setRandomCode(String randomCode) {this.randomCode=randomCode;}
}
享元工厂(相当于简单工厂的升级版):
这边存在线程安全问题,因为getWebsiteByFactory方法不是原子操作,所以我们多线程环境下一定要加锁
public class simpleFactory {/*** 享元模式是需要简单工厂模式的*/private Map<String,website> map=new HashMap<>(); //享元模式精髓private String[] colors={"red","blue","yellow","green","orange"};public website getWebsiteByFactory(String type){if(type==null||type.equals("")) {return null;}else {website website = map.get(type);if(website==null){//用简单工厂模式来书写if(type.equals("新浪")){sina sina = new sina();Random random = new Random();int index = random.nextInt(5);sina.setColor(colors[index]);int i = random.nextInt(1000);ArrayList<String> list = new ArrayList<>();list.add("hello"+i);sina.setMessages(list);sina.setRandomCode(String.valueOf(random.nextInt(9999)));map.put(type,sina);System.out.println("创建新浪网站对象成功");return sina;}else if(type.equals("知乎")){zhihu zhihu = new zhihu();Random random = new Random();zhihu.setColor(colors[random.nextInt(5)]);ArrayList<String> list = new ArrayList<>();list.add("hello"+random.nextInt(1000));zhihu.setMessages(list);zhihu.setRandomCode(String.valueOf(random.nextInt(9999)));map.put(type,zhihu);System.out.println("创建知乎网站成功");return zhihu;}else {return null;}}else {System.out.println("在享元模式的简单工厂中已经存在这个网站,所以直接获取到,没有重新创建对象");return website;}}}}
测试:
public class main {private static final String[] websites={"新浪","知乎"};public static void main(String[] args) {simpleFactory simpleFactory = new simpleFactory(); //创建享元模式的简单工厂website s1 = simpleFactory.getWebsiteByFactory("新浪");System.out.println(s1); //会创建对象/*** 享元模式重要作用之一:定制对象*/s1.setColor("利用享元模式定制对象");website s2 = simpleFactory.getWebsiteByFactory("新浪");System.out.println(s2); //不会创建对象,而是从map里面拿Random random = new Random();// for (int i = 0; i < 20; i++) {// new Thread(()->{// website website = simpleFactory.getWebsiteByFactory(websites[random.nextInt(2)]);
// System.out.println(website);
//
// }).start();
// }}}
输出结果:
创建新浪网站对象成功
sina{type='新浪', color='red', messages=[hello713], randomCode='2522'}
在享元模式的简单工厂中已经存在这个网站,所以直接获取到,没有重新创建对象
sina{type='新浪', color='利用享元模式定制对象', messages=[hello713], randomCode='2522'}
多线程环境下的问题
只需在getWebsiteByFactory方法上加锁即可
public class simpleFactory {/*** 享元模式是需要简单工厂模式的*/private Map<String,website> map=new HashMap<>(); //享元模式精髓private String[] colors={"red","blue","yellow","green","orange"};public synchronized website getWebsiteByFactory(String type){
组合模式(树型结构)
组合模式的项目应用:实现多级菜单 、文件夹的管理
组合模式我们把它看成一种“树”型结构,固然后面我们在打印这些内容的时候是需要用递归的
因为组合模式是按照树形结构来组合的,所以也有树的特点(比如:叶子节点)
案例:利用组合模式来实现三级菜单。
定义组合模式的菜单组件接口,并定义添加、删除、展示结点方法:
public interface component {/*** 组件接口:所有菜单都要实现这个component(组件)接口* 组合模式所需方法:添加结点、删除结点、打印菜单*///需要给这个添加结点一个默认实现,因为我们的叶子结点不需要添加结点和删除结点这两个方法default void addNode(component component){throw new UnsupportedOperationException();//默认抛出不支持操作异常}default void deleteNode(component component){throw new UnsupportedOperationException();}//打印===都需要实现void showMenu();}
菜单组件实现类(非叶子结点==第一、二级菜单):
一级菜单:
public class firstMenu implements component {/*** 一级菜单*/private String name; //菜单名称private List<component> components;public firstMenu(String name){this.name=name;this.components=new ArrayList<>();}@Overridepublic void addNode(component component) {components.add(component);}@Overridepublic void deleteNode(component component) {components.remove(component);}@Overridepublic void showMenu() {System.out.println("---"+this.getName()); //打印当前调用者的名称if(components.size()>0){for (component component : components) {component.showMenu(); //递归的调用这个showMenu方法}}}public String getName() {return name;}public void setName(String name) {this.name = name;}public List<component> getComponents() {return components;}public void setComponents(List<component> components) {this.components = components;}
}
二级菜单:
public class secondMenu implements component {/*** 二级菜单*/private String name;private List<component> components;public secondMenu(String name){this.name=name;this.components=new ArrayList<>();}@Overridepublic void addNode(component component) {components.add(component);}@Overridepublic void deleteNode(component component) {components.remove(component);}@Overridepublic void showMenu() {System.out.println("------"+this.getName());if(components.size()>0){for (component component : components) {component.showMenu();;}}}public String getName() {return name;}public void setName(String name) {this.name = name;}public List<component> getComponents() {return components;}public void setComponents(List<component> components) {this.components = components;}
}
三级菜单:(叶子节点),没有添加、删除结点方法
public class lastMenu implements component {private String name;/*** 最后一个菜单(三级菜单):不能添加和删除,因为它是树的叶子结点*/public lastMenu(String name){this.name=name;}@Overridepublic void showMenu() {System.out.println("---------"+this.name);}
}
组合模式客户端代码:
public class client {/*** 组合模式客户端* @param args*/public static void main(String[] args) {//创建一级菜单component f1=new firstMenu("用户列表");//创建二级菜单component s1=new secondMenu("用户信息");component s2=new secondMenu("用户权限");component s3=new secondMenu("用户好友");//创建三级菜单component l1=new lastMenu("信息修改");component l2=new lastMenu("信息删除");component l3=new lastMenu("修改权限");component l4=new lastMenu("添加好友");component l5=new lastMenu("删除好友");component l6=new lastMenu("修改好友信息");//进行组合f1.addNode(s1);f1.addNode(s2);f1.addNode(s3);s1.addNode(l1);s1.addNode(l2);s2.addNode(l3);s3.addNode(l4);s3.addNode(l5);s3.addNode(l6);//展示菜单f1.showMenu();}}
输出结果:
---用户列表
------用户信息
---------信息修改
---------信息删除
------用户权限
---------修改权限
------用户好友
---------添加好友
---------删除好友
---------修改好友信息
外观模式
为什么会有外观模式?外观模式能解决什么?其实就是把其他对象调用方法封装到外观类上,我们只需要通过调用外观类的方法就可以调用其他类的方法
总结:外观模式(门面模式)说白了就是把多个不同对象(类)的方法归纳到一个门面类(外观类)中,这样省去频繁创建对象,核心就是门面类
使用两种方法实现案例“买水果问题”。。
传统方式(买水果问题):
苹果实体类:
public class apple {/*** 苹果实体类*/private String id;private String name;public apple(String name){this.name=name;}public void setId(String id) {this.id = id;}public String getName() {return name;}@Overridepublic String toString() {return "apple{" +"id='" + id + '\'' +", name='" + name + '\'' +'}';}
}
public class banana {/*** 香蕉实体类*/private String id;private String name;public banana(String name){this.name=name;}public void setId(String id) {this.id = id;}public String getName() {return name;}@Overridepublic String toString() {return "banana{" +"id='" + id + '\'' +", name='" + name + '\'' +'}';}
}
public class orange {/*** 橙子实体类*/private String id;private String name;public orange(String name){this.name=name;}public void setId(String id) {this.id = id;}public String getName() {return name;}@Overridepublic String toString() {return "orange{" +"id='" + id + '\'' +", name='" + name + '\'' +'}';}
}
创建各自的商店:
public class appleStore {/*** 苹果专卖店*///买苹果public apple buyApple(){apple apple = new apple("苹果");apple.setId(UUID.randomUUID().toString().replaceAll("-",""));return apple;}}
public class bananaStore {//香蕉实体店public banana buyBanana(){banana banana = new banana("香蕉");banana.setId(UUID.randomUUID().toString().replaceAll("-",""));return banana;}
}
public class orangeStore {//橙子实体店public orange buyOrange(){orange orange=new orange("橙子");orange.setId(UUID.randomUUID().toString().replaceAll("-",""));return orange;}}
顾客买水果:
public class client {public static void main(String[] args) {//买苹果//1.创建苹果店对象appleStore appleStore = new appleStore();//2.购买apple apple = appleStore.buyApple();//买香蕉bananaStore bananaStore = new bananaStore();banana banana = bananaStore.buyBanana();//买橙子orangeStore orangeStore = new orangeStore();orange orange = orangeStore.buyOrange();System.out.println(apple);System.out.println(banana);System.out.println(orange);}}
**====================**
总结:可以看出来使用传统方法买水果比较复杂,顾客需要创建各自的商店,再去购买。。。
外观模式(买水果问题):
上面实体类不变,只需要添加一个门面类(外观类)即可
核心(外观类):
public class myFacade {/*** 创建门面类(外观类)*///这几个变量也可以写成单例,这里暂且不写private appleStore appleStore;private bananaStore bananaStore;private orangeStore orangeStore;public myFacade(){//初始化对象this.appleStore=new appleStore();this.bananaStore=new bananaStore();this.orangeStore=new orangeStore();}/*** 精髓。。。* 使用外观模式的外观类来归纳方法,把多个类的方法归纳到一个外观类中* @return*///创建门面方法(外观方法),购买水果//买苹果public apple buyAppleByfacade(){apple apple = appleStore.buyApple();apple.setId(UUID.randomUUID().toString().replaceAll("-",""));return apple;}//买香蕉public banana buyBananaByfacade(){banana banana = bananaStore.buyBanana();banana.setId(UUID.randomUUID().toString().replaceAll("-",""));return banana;}//买橙子public orange buyOrangeByfacade(){orange orange = orangeStore.buyOrange();orange.setId(UUID.randomUUID().toString().replaceAll("-",""));return orange;}}
public class client {public static void main(String[] args) {//创建已经归纳好方法的外观类myFacade myFacade = new myFacade();//购买水果apple apple = myFacade.buyAppleByfacade();banana banana = myFacade.buyBananaByfacade();orange orange = myFacade.buyOrangeByfacade();System.out.println(apple);System.out.println(banana);System.out.println(orange);}
}
这时候我们不需要创建商店了,只需要创建外观类调用买水果方法即可。
外观模式优点:假如水果有1000种,那么我们就要创建1000个对象,而使用外观模式,只需要创建一个外观类的对象即可,只需要1个对象。这样对比起来就相当明显了。。。。。。。。。。。。。。。。。。
桥接模式
使用桥接类和需要被桥接的接口进行桥接
案例:假设我们需要一个接口,用来连接mysql或者Oracle
public interface connection {public void connectDatasource();}
public class connection_mysql implements connection {/*连接mysql数据源*/@Overridepublic void connectDatasource() {System.out.println("mysql数据源连接成功!!!");}
}
public class connection_oracle implements connection {/*连接Oracle数据源*/@Overridepublic void connectDatasource() {System.out.println("oracle数据源连接成功!!!");}
}
传统方式测试:
public class client_chuantong {public static void main(String[] args) {//传统方法调用接口方法connection connection=new connection_mysql();connection.connectDatasource();connection connection1=new connection_oracle();connection.connectDatasource();}}
桥的抽象类:
public abstract class bridge {/*** 桥的抽象类*/public abstract void connection();}
桥的实现类
public class bridgeImpl extends bridge {/*** 核心* 使用了桥接模式之后,我们只需要创建桥接*/private connection connection;//给对象注入public bridgeImpl(connection connection){this.connection=connection;}//桥接方法(桥接接口方法)@Overridepublic void connection() {connection.connectDatasource();}
}
桥接测试:
public class client_bridge {public static void main(String[] args) {//使用桥接实现类调用被桥接的接口方法bridge bridge = new bridgeImpl(new connection_oracle());bridge.connection();}}
观察者模式
既然有观察者,那么也就有被观察者。一个被观察者被多个观察者观察。比如说天气预报,天气预报就是被观察者,订阅了天气预报的人就是观察者,天气预报需要通知观察者。
被观察者接口:
public interface observerable {/*** 被观察者*///添加观察者public void addObserver(observer observer);//移除观察者public void removeObserver(observer observer);//通知所有观察者public void notifyAllObserver();}
观察者接口:
public interface observer {/*** 观察者*///接收通知的方法public void getTianqi(tianqi tianqi);}
被观察者(在这是天气预报):
public class tianqi implements observerable {/*** 被观察者 :天气预报*/private String date;//日期private String wendu;//摄氏度private List<observer> observers; //管理所有观察者,以便通知观察者们(其实也就是调用观察者的接收通知方法)public tianqi(){this.observers=new ArrayList<>();this.date="2021/5/9";this.wendu="37°C";}public tianqi(String date, String wendu) {this.date=date;this.wendu=wendu;}public String getDate() {return date;}public void setDate(String date) {this.date = date;}public String getWendu() {return wendu;}public void setWendu(String wendu) {this.wendu = wendu;}@Overridepublic void addObserver(observer observer) {observers.add(observer);}@Overridepublic void removeObserver(observer observer) {observers.remove(observer);}@Overridepublic void notifyAllObserver() {if(observers.size()>0){for (int i = 0; i < observers.size(); i++) {observers.get(i).getTianqi(new tianqi(this.date,this.wendu));}}else{System.out.println("没有人订阅过天气预报。。。");}}@Overridepublic String toString() {return "天气信息{" +"date='" + date + '\'' +", wendu='" + wendu + '\'' +'}';}
}
观察者:
public class person implements observer {/*** 人:观察者*/private String name; //观察者名字public person(String name){this.name=name;}@Overridepublic void getTianqi(tianqi tianqi) {System.out.println("当前用户名为:"+name+","+tianqi);}
}
客户端(测试):
public class client {public static void main(String[] args) {tianqi tianqi = new tianqi();tianqi.addObserver(new person("小明"));tianqi.addObserver(new person("小华"));tianqi.notifyAllObserver();System.out.println("=======修改后");tianqi.addObserver(new person("小刘"));tianqi.setDate("2021/5/10");tianqi.setWendu("15°C");tianqi.notifyAllObserver();}}
备忘录模式
备忘录模式:可以用来备份数据和恢复
备忘录需要有三个类:需要备份的类、originator(生成需要备份的类的对象),存储数据和恢复数据的类
责任链模式
策略模式
模板模式
Java实现23种设计模式教程(作者原创)相关推荐
- java 的23种设计模式 之单身狗和隔壁老王的故事
2019独角兽企业重金招聘Python工程师标准>>> 觉得代码写的别扭了,回头翻翻java 的23种设计模式. today,额,这么晚了,困了.就弄个最简单的单例模式吧. 单例模式 ...
- 经典:从追MM谈Java的23种设计模式
2019独角兽企业重金招聘Python工程师标准>>> 从追MM谈Java的23种设计模式1.FACTORY-追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,虽然 ...
- 从追MM谈Java的23种设计模式
设计模式做为程序员的"内功心法",越来越受到.net 社区的重视,这种变化是很可喜的,Java社区走在了我们的前面,但这种状况 也许有一天会发生改变. {虽然有点长,但是相信相当经 ...
- Java进阶 23种设计模式 详解+应用+实例代码
文章目录 前言 设计模式六大原则 1.单一原则 (1) 概念 (2) 优点 2.开闭原则 (1) 概念 3.里氏替换原则 (1) 概念 4.依赖倒置原则 (1) 概念 (2) 作用 5.接口隔离原则 ...
- Java中23种设计模式(随时不定时更新)
一.创建型模式 1.单例模式(Singleton Pattern) 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种模式涉及到一个单一的类,该类负责创建自己的对 ...
- java与23种设计模式
1 23种设计模式分类 经典的<设计模式>一书归纳出23种设计模式,本文按<易学设计模式>一书归纳分类如下: 1.创建型模式 前面讲过,社会化的分工越来越细,自然在软件设计方面 ...
- java 的23种设计模式 单例模式
23种设计模式友情链接: 点击打开链接 单例模式: A.饿汉式单例模式 具体步骤: 1.声明一个私有的静态的最终的本类类型的对象并实例化 private static final Person ins ...
- 关于Java的23种设计模式的有趣见解
2019独角兽企业重金招聘Python工程师标准>>> 在网上看见了这篇文章,作者以轻松的语言比喻了java的32种模式,有很好的启发作用. 好东西不得不转 创建型模式 1.FACT ...
- Java的23种设计模式(搞笑版)
我在Java论坛看到这篇文章,作者以轻松的语言比喻了java的32种模式,有很好的启发作用,但可惜没有给出具体的意思,我就在后边加上了.这些都是最简单的介绍,要学习的话建议你看一下阎宏博士的<J ...
最新文章
- java冒泡排序函数验证_java冒泡排序-选择排序-插入排序-使用API中文文档直接调用函数...
- 谷歌砸出10亿美元,要为湾区困难群众,建2万套经适房
- 利用Eclipse的Update组件实现适合企业应用的更新组件(1)
- C++ Queues(队列)
- thinkphp mysql函数_thinkphp对数据库操作有哪些内置函数
- 配置生产环境加路径 /开发环境
- php中如何使用html代码
- Java内存模型JMM简单分析
- 中兴e8820刷openwrt_中兴E8820V2(电信天翼宽带类似新路由3歌华链)-拆机及OpenWrt固件...
- clearcase Commands
- 坚果J10和当贝F3体验分享,智能家用投影仪究竟应该怎么选?
- 告别“霍金音”:华裔科学家设计脑机新设备,人类首次直接用脑波“说话”...
- 【5】依赖注入DI(Dependency Injection)
- Access数据库教程_如何进行C#连接Access数据库的细节操作?
- Saas发展史常用架构
- 西工大计算机操作系统实验报告,西工大计算机操作系统课程设计实验报告bh05xh5...
- 喜报|炼石斩获双项2021中国网络安全与信息产业金智奖
- 【GNN】VGAE:利用变分自编码器完成图重构
- cl.5fy.php,近期选手转会:Scarlett、Bly离队Cl
- 阿根廷绝杀尼日尼亚给我们互联网建站者带来什么启示?
热门文章
- Window10蓝牙无法连接的解决方案(已成功)
- 计算机无法连接蓝牙键盘,Windows10下蓝牙键盘连接后使用不了如何解决
- 特斯拉充电电流设置多大_【干货】特斯拉电动汽车4种充电方式详解!
- 计算机光驱图标符号,电脑不显示光驱图标怎么解决
- 已知信码序列为1011_专升本计算机网络:校验码
- zhong yu gong si
- win10查看打印机端口
- 深度解析CTM项目成功的原因
- word流程图怎么使箭头对齐_工作流程图的方框怎样平均纵横对齐:又怎样 让箭头对齐到流程图方框线中间,请教了。...
- 安卓微信跳转页面、重定向页面空白,ios系统正常、pc正常、安卓浏览器正常。