目录
设计模式六大原则
1.单一职责原则:
一个类只负责一个一个单一的功能,其他的无关需求发生变更时候不影响此类。
2.里氏替换原则:
所有引用基类的地方,一定能使用其子类(子类型必须能够替换掉它们的父类型)
3.依赖倒置原则:
抽象(接口)应该是一切模块的依赖起源。具体的实现(细节),应该依赖于接口(抽象)而存在;
有需求变化时可以直接修改具体实现,而不更改接口
4.接口隔离原则:
不依赖不需要的接口,将对其他类的依赖降到最小,使用多个相互隔离的接口
5.迪米特法则:
一个类应当尽量少地与其他类之间发生相互作用(降低耦合度),使得系统功能模块相对独立。
6.开闭原则:
对一个类开放扩展,但是不开放修改(一旦开发完成,就不再需要对这个类做修改)。
一. 单例模式
单例模式,简单来说,就是一整个项目功能,对应某个类来说都只有一个实例,不产生多个实例。
不对外提供构造方法,让外部无法随意的新建此类的实例;如果想获得此类实例,只能通过此类对外提
供的方法获得(一般为getInstance()方法)。
1. 简单单例(懒汉、线程不安全)
为什么叫懒汉式呢,因为你看,他是不用就不new的。只有当有需求要使用,调到getInstance方法的时候,如果不存在才会new
/**
* 懒汉式单例(我不饿,等我饿了再实例化)
* @author kevin
* @date 2021/1/28
*/
public class LazySingleton {
private static LazySingleton singleton;
private LazySingleton(){
}
/**
* 获取实例,判断在没有实例的时候才获取实例
* @author kevin
* @return com.liu.test.singleton.LazySingleton
* @date 2021/1/28 11:06
*/
public static LazySingleton getInstance(){
if(singleton == null){
singleton = new LazySingleton();
}
return singleton;
}
}
2. 懒汉式单例(线程安全)
为什么叫懒汉式呢,因为你看,他是不用就不new的。只有当有需求要使用,调到getInstance方法的时候,如果不存在才会new
/**
* 懒汉式单例(我不饿,等我饿了再实例化)
* @author kevin
* @date 2021/1/28
*/
public class SafeLazySingleton {
private static SafeLazySingleton singleton;
private SafeLazySingleton(){
}
/**
* 获取实例,判断在没有实例的时候才获取实例(切线程安全)
* @author kevin
* @return com.liu.test.singleton.LazySingleton
* @date 2021/1/28 11:06
*/
public static synchronized SafeLazySingleton getInstance(){
if(singleton == null){
singleton = new SafeLazySingleton();
}
return singleton;
}
}
3. 饿汉式单例
为什么叫饿汉式呢,因为你应该已经发现了,它不管三七二十一,直接在定义类的静态属性对象的直接就直接new了
/**
* 饿汉式单例(太饿了,早早的就实例化好了)
* @author kevin
* @date 2021/1/28
*/
public class HungrySingleton {
//类加载的时候就生成静态变量实例,需要的时候直接返回
private static final HungrySingleton singleton = new HungrySingleton();
private HungrySingleton(){
}
/**
* 获取实例,直接返回
* @author kevin
* @return com.liu.test.singleton.LazySingleton
* @date 2021/1/28 11:06
*/
public static synchronized HungrySingleton getInstance(){
return singleton;
}
}
4. 静态内部类方式
直接定义一个静态内部类,在静态的内部类中定义静态变量接受一个new出来的实例;
/**
* 静态内部类(其实也算是饿汉式)
* @author kevin
* @date 2021/1/28
*/
public class StaticInnerClassSingleton {
private StaticInnerClassSingleton(){
}
/**
* 静态的内部类
* @author kevin
* @date 2021/1/28
*/
private static class SingletonBuilder{
private static final StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton();
}
/**
* 获取实例,直接返回内部类中的静态变量实例,并且方法是final的
* @author kevin
* @return com.liu.test.singleton.StaticInnerClassSingleton
* @date 2021/1/28 11:22
*/
public static final StaticInnerClassSingleton getInstance(){
return SingletonBuilder.INSTANCE;
}
}
5. 双重检查锁+volatile方式
两次检查类实例是否已经存在,第一次不加锁,在第二次检查的时候加锁(减少了锁的范围);并且使用volatile,保证实例变量对所有线程可见(任何一个线程修改了,其他线程能立即同步)
/**
* 双重锁校验(个人理解算是饿汉式的一种吧)
* @author kevin
* @date 2021/1/28
*/
public class DoubleCheckSingleton {
private static volatile DoubleCheckSingleton singleton;
private DoubleCheckSingleton(){
}
/**
* 获取实例,判断如果为空才进行加锁获取
* @author kevin
* @return com.liu.test.singleton.DoubleCheckSingleton
* @date 2021/1/28 11:35
*/
public static final DoubleCheckSingleton getInstance(){
if (singleton == null){
//对即将实例化的类加锁(锁住判断实例为空创建实例的过程)
synchronized (DoubleCheckSingleton.class){
if (singleton == null){
singleton = new DoubleCheckSingleton();
}
}
}
return singleton;
}
}
二、工厂模式
参考作者另外一篇文章:https://blog.csdn.net/liu649983697/article/details/113181670
三、代理模式
为其他对象提供一种代理以控制对这个对象的访问。代理对象起到中介作用,可去掉功能服务或增加额外
的服务。
个人理解,代理模式很好理解,一个简单的例子:有一天,你和你的同事都在晚上加班,到了11点的时候
,你和你的同事都觉得肚子很饿,然后你们就商量一定得买点吃的了,不然太容易得胃病啦;所以最后商量的
结果是你同事下去买吃的,你继续留守岗位,然后你让你的同事帮你带吃的回来,让他给你带一份炒菜,你给
他钱等着吃的回来就行了。这就是代理,你委托你的同事帮你买吃的,你的同事就是代理的角色。
代理模式:分为静态代理与动态代理两种。
1.静态代理
在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了
定义带吃的接口
public interface ITakeFood {
String takeFood();
}
定义用户类
import com.liu.test.designpattern.proxy.ITakeFood;
public class TakeFoodImpl implements ITakeFood {
@Override
public String takeFood(){
return "炒菜";
}
}
定义代理类
你的同事觉得你只要炒菜吃不饱,所以给你增加了米饭
import com.liu.test.designpattern.proxy.ITakeFood;
public class TakeFoodPoxy implements ITakeFood {
private ITakeFood iTakeFood;
public TakeFoodPoxy(ITakeFood iTakeFood){
this.iTakeFood = iTakeFood;
}
@Override
public String takeFood(){
String food = iTakeFood.takeFood();
food = food.concat("+米饭");
return food;
}
}
使用代理
/**
* 测试代理模式-静态代理
*
* @return java.lang.String
* @author kevin
* @date 2021/1/28 18:36
*/
@Override
public String testStaticProxy() {
TakeFoodPoxy takeFood = new TakeFoodPoxy(new TakeFoodImpl());
return takeFood.takeFood();
}
2.JDK动态代理
动态代理具有更强的灵活性,因为它不用在我们设计实现的时候就指定某一个代理类来代理哪一个被代理对
象,而是把这种指定延迟到程序运行时由JVM来实现。使用静态代理代码,
增加handler
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class TakeFoodHandler implements InvocationHandler {
private Object object;
public TakeFoodHandler(Object o){
this.object = o;
}
/**
* 实现接口的invoke方法
* @author kevin
* @param proxy :
* @param method :
* @param args :
* @return java.lang.Object
* @date 2021/1/28 19:04
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//调用前
dealBefore();
//反射调用
Object result = method.invoke(object, args);
//调用后
dealAfter();
return result;
}
/**
* 前置逻辑
* @author kevin
* @date 2021/1/28 21:36
*/
private void dealBefore() {
System.out.println("先给我钱吧!");
}
/**
* 后置逻辑
* @author kevin
* @date 2021/1/28 21:36
*/
private void dealAfter() {
System.out.println("饭给你带回来了!");
}
}
修改调用方式
/**
* 测试代理模式-jdk动态代理
*
* @return java.lang.String
* @author kevin
* @date 2021/1/28 19:02
*/
@Override
public String testJDKDynamicProxy() {
TakeFoodImpl takeFood = new TakeFoodImpl();
TakeFoodHandler takeFoodHandler = new TakeFoodHandler(takeFood);
//准备类加载器
ClassLoader loader = TakeFoodImpl.class.getClassLoader();
//获取目标对象的接口类对象数组
Class<?>[] interfaces = takeFood.getClass().getInterfaces();
//创建代理
TakeFood proxy = (TakeFood) Proxy.newProxyInstance(loader, interfaces, takeFoodHandler);
return proxy.takeFood();
}
3.CGLib动态代理
引入cglib的依赖:
<!-- cglib动态代理 -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
编写增强器:
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 类描述
* @author kevin
* @date 2021/1/28
*/
public class CGLibProxy implements MethodInterceptor {
//饿汉单例模式
private static CGLibProxy instance = new CGLibProxy();
private CGLibProxy() {
}
public static CGLibProxy getInstance () {
return instance;
}
/**
* 创建代理对象
* @author kevin
* @param cls : 被代理业务类
* @return T
* @date 2021/1/28 21:30
*/
public <T> T getProxy(Class<T> cls) {
//创建增强器
//cls 成被代理业务类(TakeFood)的子类;被代理业务类不能使用final修饰。
//this,设置callback,被代理业务类所有方法,通过此调用
return (T) Enhancer.create(cls, this);
}
/**
* 拦截器,在方法请求前拦截处理增加逻辑
* @author kevin
* @param obj :
* @param method :
* @param objects :
* @param methodProxy :
* @return java.lang.Object
* @date 2021/1/28 21:35
*/
@Override
public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
dealBefore();
//调用父类中的方法
Object result = methodProxy.invokeSuper(obj, objects);
dealAfter();
return result;
}
/**
* 前置逻辑
* @author kevin
* @date 2021/1/28 21:36
*/
private void dealBefore() {
System.out.println("先给我钱吧!");
}
/**
* 后置逻辑
* @author kevin
* @date 2021/1/28 21:36
*/
private void dealAfter() {
System.out.println("饭给你带回来了!");
}
}
修改使用:
/**
* 测试代理模式-cglib动态代理
*
* @return java.lang.String
* @author kevin
* @date 2021/1/28 20:52
*/
@Override
public String testCGLIBDynamicProxy() {
TakeFood takeFood = CGLibProxy.getInstance().getProxy(TakeFood.class);
return takeFood.takeFood();
}
使用Java动态代理机制的好处:
1、减少编程的工作量:如需要实现多种代理处理逻辑,只要写多个代理处理器就可以了,无需每种方式都写一个代理类。
2、系统扩展性和维护性增强,一般只要改代理处理器类就行了。
3、可以在不影响原有业务的基础上增加与原业务逻辑无影响的其他业务逻辑。
四、观察者模式
在对象之间定义了一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象会收到通知并自动更新。
观察者模式中,有两个角色,观察者与被观察者;观察者一直关注着被观察者,当被观察者有变化的时候,
所有的观察者马上就能感知到。
举个例子,阿里公司有自己的规章制度,马云来制定具体的规章制度(假设,别当真)制定好规章制定后发
布到阿里公司的群公告里;然后阿里的员工需要遵守规章制度公告,那就需要知道规章制度,所以阿里员工需要
关注群里的公告,每当马云更新群公告规章制度的时候,群里所有员工都会得到群公告更新的通知-规章制度变化
了,所有加群的员工都知道了最新的规章制度。
程序大致包含四个类,就是有一个观察者接口,一个观察者接口实现类;一个被观察者接口,一个被观察者
接口实现类;观察者接口提供两个方法:接受消息的方法、读取消息的方法;被观察者接口,提供四个方法:观察
者注册方法、观察者注销方法、通知所有观察者消息方法、改变消息方法。UML画图:
注:IObserver接口与实现类中的getObserverName以及IObserved接口与实现类中的getObserverByName、
doChange是作者为了方便自己测试,增加的方法定义与实现。
代码大致如下(与单独的测试类有区别-因为是写在自己的一个测试项目中,使用接口来测试的):
1.观察者接口:
import net.sf.json.JSONObject;
/**
* 观察者接口
* @author kevin
* @date 2021/1/28
*/
public interface IObserver {
/**
* 获取观察者名字
* @author kevin
* @return java.lang.String
* @date 2021/1/28 16:33
*/
String getObserverName();
/**
* 接受被观察者的变化信息
* @author kevin
* @param object :
* @date 2021/1/28 14:51
*/
void receiveUpdate(JSONObject object);
/**
* 读取消息
* @author kevin
* @return net.sf.json.JSONObject
* @date 2021/1/28 15:28
*/
JSONObject readMessage();
}
2.观察者实现:
import com.liu.test.observerpattern.IObserver;
import net.sf.json.JSONObject;
public class AliObserverImpl implements IObserver {
private JSONObject messageBody = null;
public String getObserverName() {
return observerName;
}
private String observerName = "";
public AliObserverImpl(String observerName) {
this.observerName = observerName;
}
/**
* 接受被观察者的变化信息
* @param object :
* @author kevin
* @date 2021/1/28 14:51
*/
@Override
public void receiveUpdate(JSONObject object) {
object.put("msg", "我是:" + observerName + ",收到消息:" + object.getString("msg"));
System.out.println(object.getString("msg"));
this.messageBody = object;
}
/**
* 读取消息
* @author kevin
* @return net.sf.json.JSONObject
* @date 2021/1/28 14:58
*/
public JSONObject readMessage(){
return messageBody;
}
}
3.被观察者接口:
/**
* 被观察者接口
* @author kevin
* @date 2021/1/28
*/
public interface IObserved {
/**
* 观察者开始观察
* @author kevin
* @param observer :
* @date 2021/1/28 14:46
*/
void beginObserve(IObserver observer);
/**
* 观察者停止观察
* @author kevin
* @param userName :
* @date 2021/1/28 14:46
*/
void stopObserve(String userName);
/**
* 通知所有观察者变化
* @author kevin
* @date 2021/1/28 14:47
*/
void notifyObserver();
}
4.被观察者实现:
import com.liu.test.observerpattern.IObserved;
import com.liu.test.observerpattern.IObserver;
import net.sf.json.JSONObject;
import org.springframework.util.CollectionUtils;
import java.util.HashMap;
import java.util.Map;
/**
* 被观察者的具体被观察对象(阿里规章制度)
* @author kevin
* @date 2021/1/28
*/
public class AliObservedImpl implements IObserved {
private static final AliObservedImpl aliObserved = new AliObservedImpl();
private static final Map<String,IObserver> observers = new HashMap<>();
private static final JSONObject messageBody = new JSONObject();
public static final AliObservedImpl getInstance(){
return aliObserved;
}
public final IObserver getObserverByName(String userName){
return observers.get(userName);
}
/**
* 观察者开始观察
* @param observer :
* @author kevin
* @date 2021/1/28 14:46
*/
@Override
public void beginObserve(IObserver observer) {
observers.put(observer.getObserverName(), observer);
}
/**
* 观察者停止观察
* @param userName :
* @author kevin
* @date 2021/1/28 14:46
*/
@Override
public void stopObserve(String userName) {
if(!CollectionUtils.isEmpty(observers)) {
observers.remove(userName);
}
}
/**
* 通知所有观察者变化
* @author kevin
* @date 2021/1/28 14:47
*/
@Override
public void notifyObserver() {
for(IObserver observer : observers.values()){
observer.receiveUpdate(messageBody);
}
}
/**
* 消息进行变化
* @author kevin
* @param msg :
* @date 2021/1/28 14:55
*/
public void doChange(String msg){
messageBody.put("msg", msg);
//消息变更后,要通知所有观察者变化
notifyObserver();
}
}
5.调用使用:
/**
* 测试观察者模式-观察者注册
* @author kevin
* @param userName :
* @date 2021/1/28 16:27
*/
@Override
public void testObserverBegin(String userName) {
IObserver observer = new AliObserverImpl(userName);
//观察者开始观察
AliObservedImpl observed = AliObservedImpl.getInstance();
observed.beginObserve(observer);
//被观察者发布消息
observed.doChange("今天晚上加班到12点!");
}
/**
* 测试观察者模式-观察者注销
* @param userName :
* @author kevin
* @date 2021/1/28 16:29
*/
@Override
public void testObserverStop(String userName) {
//观察者停止观察
AliObservedImpl observed = AliObservedImpl.getInstance();
observed.stopObserve(userName);
}
/**
* 测试观察者模式-被观察者变化
* @param msg :
* @author kevin
* @date 2021/1/28 16:38
*/
@Override
public void testObservedChange(String msg) {
//被观察者变化
AliObservedImpl observed = AliObservedImpl.getInstance();
observed.doChange(msg);
}
/**
* 测试观察者模式-观察者读取信息
* @author kevin
* @param userName :
* @return java.lang.String
* @date 2021/1/28 16:45
*/
@Override
public String testObserverRead(String userName) {
AliObservedImpl observed = AliObservedImpl.getInstance();
JSONObject result = observed.getObserverByName(userName).readMessage();
return null == result ? "" : result.getString("msg");
}
五、建造者模式
将一个复杂对象的构建与它的属性分离,使得同样的构建过程可以创建不同的表示;用户只需要了解自己关注的部分业务实现,而不用了解所有的业务实现。建造者模式主要是用来解决复杂对象的创建问题,它跟工厂模式正好关注点相反,它关注的是创建的过程,而工厂模式关注的创建的结果。建造者模式主要有4个模块-建造者接口、建造者实现、调度者、被建造对象。
如:我们要创造一个开发者,开发者假设有三个属性-性别、年龄、技能。但是每个开发者肯定是不一样的。所以不同的开发者实例也是不一样的,年龄、性别、技能不尽相同;我们可以将三个属性的构造抽象出来提供一个接口(建造者接口),然后不同的开发者去实现这个接口与其方法(建造者实现),然后再通过一个调度者(调度者)去创建具体的开发人员实例(被建造对象)。代码如下:
1.抽象建造者接口
package com.liu.test.builder;
public interface IBuilder {
void setSex(String sex);
void setAge(Integer age);
void setSkill(String skill);
Developer build();
}
2.建造者接口实现
package com.liu.test.builder.impl;
import com.liu.test.builder.Developer;
import com.liu.test.builder.IBuilder;
public class DeveloperBuilder implements IBuilder {
private Developer developer;
public DeveloperBuilder() {
this.developer = new Developer();
}
public void setSex(String sex) {
developer.setSex(sex);
}
public void setAge(Integer age) {
developer.setAge(age);
}
public void setSkill(String skill) {
developer.setSkill(skill);
}
public Developer build() {
return developer;
}
}
3.调度者
package com.liu.test.builder;
public class DeveloperDirector {
public static Developer createDeveloper(IBuilder builder, String sex, String skill, Integer age){
builder.setSex(sex);
builder.setAge(age);
builder.setSkill(skill);
return builder.build();
}
}
4.被建造对象
package com.liu.test.builder;
@SuppressWarnings({"unused"})
public class Developer {
private String sex;
private Integer age;
private String skill;
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getSkill() {
return skill;
}
public void setSkill(String skill) {
this.skill = skill;
}
@Override
public String toString() {
return "Developer{" +
"sex='" + sex + '\'' +
", age=" + age +
", skill='" + skill + '\'' +
'}';
}
}
5.使用
package com.liu.test.builder;
import com.liu.test.builder.impl.DeveloperBuilder;
public class Test {
public static void main(String[] args) {
Developer developer = DeveloperDirector.createDeveloper(new DeveloperBuilder(),"男","java",24);
System.out.println(developer);
developer = DeveloperDirector.createDeveloper(new DeveloperBuilder(),"女","python",23);
System.out.println(developer);
}
}
6.以静态内部类方式替代实现
作者理解这并不是建造者模式,只是链试调用责任链模式实现创建
一个简单的springboot项目restful风格统一返回的定义;如果需要其他的设置属性方法,自行添加即可,作者更倾向于这种方式(简单直接好理解):
import com.alibaba.fastjson.JSONObject;
import com.cetccloud.constants.enums.ResponseState;
/**
* 控制层统一返回对象
* @author kevin
* @Date 2021/2/1
*/
@SuppressWarnings({"unused"})
public class ResponseData{
/* 码值 */
private Integer code;
/*是否成功*/
private Boolean success;
/* 消息 */
private String message;
/* 数据 */
private Object data = new JSONObject();
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public Boolean getSuccess() {
return success;
}
public void setSuccess(Boolean success) {
this.success = success;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public static class Builder {
private Integer code;
private Boolean success;
private String message;
private Object data;
public Builder code(Integer builderCode) {
code = builderCode;
return this;
}
public Builder message(String builderMessage) {
message = builderMessage;
return this;
}
public Builder data(Object builderData) {
data = builderData;
return this;
}
public Builder success(Boolean builderSuccess) {
success= builderSuccess;
return this;
}
public Builder ok() {
code = 200;
message = "请求成功";
success = true;
return this;
}
public Builder error() {
code = 201;
message = "请求失败";
success = false;
return this;
}
public Builder error(int errCode) {
code = errCode;
message = "请求失败";
success = false;
return this;
}
public ResponseData build() {
return new ResponseData(this);
}
}
private ResponseData(Builder builder) {
code = builder.code;
success = builder.success;
message = builder.message;
data = builder.data;
}
}
六、生产者-消费者模式
生产者-消费者模式,是一个线程的问题,生产者生产产品,消费者消费生产者生产的产品。生产者生产的产品放入一个容器,当容器满了,就不再继续生产,等待消费者消费产品;而消费者从容器中消费产品,直到将容器中的产品消耗完,继续等待生产者生产。举个例子:一个衣服厂生产衣服,这个厂的仓库可以存放10件衣服。工人开始生产衣服,直到生产出10件衣服堆满厂库,不再继续生产,直到衣服被买走,又继续生产;而服装店老板需要进货,从该服装厂进货,等待服装厂生产服装,一旦仓库有服装,老板就开始购买服装,直到仓库没有库存。下面开始实现,
采用LinkedBlockingQueue阻塞队列
LinkedBlockingQueue是一个阻塞的线程安全的队列,底层采用链表实现,LinkedBlockingQueue的方法大体介绍:
①. 将元素加入队列的方法如下:
add添加元素,如队列已满,抛出异常:IIIegalSlabEepeplian
put添加元素,如果队列已满,阻塞,直到队列有空间,继续添加元素
offer添加元素,如果队列已满,直接返回false。
②. 从队列中取出并移除头元素的方法如下:
poll: 移除并返回队列头部元素,如果队列为空,返回null。
remove:移除并返回队列头部元素,如果队列为空,抛出异常:NoSuchElementException
take:移除并返回队列头部元素,如果队列为空,阻塞,等待有元素。
peek:返回队列头部元素,如果队列为空,返回null。
element:返回队列头部元素,如果队列为空,抛出异常:NoSuchElementException
1.创建衣服对象
package com.liu.test.productorconsumer;
public class Dress {
private String name;
private String sex;
private Integer size;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getSize() {
return size;
}
public void setSize(Integer size) {
this.size = size;
}
@Override
public String toString() {
return "Dress{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", size=" + size +
'}';
}
}
2.创建生产者
package com.liu.test.productorconsumer;
import java.util.concurrent.BlockingQueue;
public class DressProductor implements Runnable{
//生产的衣服的序号
private static int DRESS_NUM = 0;
//阻塞队列
private BlockingQueue<Dress> dresses;
public DressProductor(BlockingQueue<Dress> dresses) {
this.dresses = dresses;
}
public void run() {
while (true){
try {
Dress dress = new Dress();
dress.setName("衣服"+(++DRESS_NUM));
dress.setSex(String.valueOf(DRESS_NUM%2).equals("1") ? "男" : "女");
dress.setSize(42);
//加入队列,如果返回false表示队列已满
if(!dresses.offer(dress)){
System.out.println("工人:" + Thread.currentThread().getName() +
" 生产衣服:" + dress + "失败,仓库已经满了,快来点人买走衣服吧!");
}else {
//看调试效果
System.out.println("工人:" + Thread.currentThread().getName() +
" 生产了一件衣服:" + dress + ",仓库衣服" + dresses.size() + "件");
}
System.out.println("休息1秒吧!");
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
Thread.currentThread().interrupt();
break;
}
}
}
}
3.创建消费者
package com.liu.test.productorconsumer;
import java.util.concurrent.BlockingQueue;
public class DressConsumer implements Runnable{
//阻塞队列
private BlockingQueue<Dress> dresses;
public DressConsumer(BlockingQueue<Dress> dresses) {
this.dresses = dresses;
}
public void run() {
while (true){
try {
//如果take返回的是null,会阻塞dresses队列,等待有内容
Dress dress = dresses.poll();
if(dress != null){
System.out.println("我是服装店老板:" + Thread.currentThread().getName() + ",我买了衣服:" + dress);
}else{
System.out.println("我是服装店老板:" + Thread.currentThread().getName() + ",我来买衣服却发现仓库没衣服了,好着急啊!");
}
//睡一秒,观察情况
System.out.println("等我先用8秒把衣服卖了!");
Thread.sleep(8000);
} catch (Exception e) {
e.printStackTrace();
System.out.println("我是服装店老板:" + Thread.currentThread().getName() + ",我买衣服出现错误了:" + e.getMessage());
Thread.currentThread().interrupt();
break;
}
}
}
}
4.编写测试
package com.liu.test.productorconsumer;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
public class Test {
public static void main(String[] args) {
//仓库总共可放10件衣服
BlockingQueue<Dress> dresses = new LinkedBlockingDeque<Dress>(10);
Thread productor = new Thread(new DressProductor(dresses),"生产者1");
Thread consumer = new Thread(new DressConsumer(dresses),"消费者1");
Thread consumer1 = new Thread(new DressConsumer(dresses),"消费者2");
productor.start();
consumer.start();
consumer1.start();
}
}
七、适配器模式
将一个类的接口转成客户期望的另外一个接口。适配器模式使得原本由于接口不匹配而不能一起工作的那些类可以一起工作。简单说来,你有一台电脑,电脑上游hdmi高清接口,但是没有VGA接口;可是你想去会议室投屏,会议室的投影仪却只支持VGA;这个时候你需要一个转接头,将你的HDMI高清接口转换为VGA接口进行投影。这个转接头就是适配器。适配器模式分为:类适配器、对象适配器、接口适配器。示例如下:
1.类适配器
使用继承的方式来实现适配。由于Java中是单继承,所以这个适配器仅仅只能服务于所继承的被适配者Computor
①. 电脑
package com.liu.test.adaptor.classadaptor;
public class Computor {
private String name = "《唐人街探案1》";
public String outputHDMIInfo(){
return this.name;
}
}
②.投影仪
package com.liu.test.adaptor.classadaptor;
public interface Projector {
String inputVGAInfo();
}
③.转接头
package com.liu.test.adaptor.classadaptor;
public class Adaptor extends Computor implements Projector {
@Override
public String inputVGAInfo() {
//接受电脑HDMI信息
String info = outputHDMIInfo();
//转换电脑HDMI信息
String myInfo = info + "-VGA";
//投影输出转换后的VGA信息
return myInfo;
}
}
④.测试
package com.liu.test.adaptor.classadaptor;
public class Test {
public static void main(String[] args) {
Projector adaptor = new Adaptor();
//适配器将HDMI信息转换成vga信息
String vgaInfo = adaptor.inputVGAInfo();
System.out.println("电脑输入HDMI信息已成功转换为VGA信息:" + vgaInfo);
}
}
2.对象适配器
使用组合的方式来实现适配。通过在适配器的构造函数中将需要被适配的类传递进来进行适配。
①. 电脑
package com.liu.test.adaptor.classadaptor;
public class Computor {
private String name = "《唐人街探案1》";
public String outputHDMIInfo(){
return this.name;
}
}
②.投影仪
package com.liu.test.adaptor.classadaptor;
public interface Projector {
String inputVGAInfo();
}
③.转接头
package com.liu.test.adaptor.objectadaptor;
public class Adaptor implements Projector {
private Computor computor;
public Adaptor(Computor computor) {
this.computor = computor;
}
@Override
public String inputVGAInfo() {
String myInfo;
//接受电脑HDMI信息
if(null != computor) {
String info = computor.outputHDMIInfo();
//转换电脑HDMI信息
myInfo = info + "-VGA";
}else {
myInfo = "未收到电脑HDMI信息";
}
//投影输出转换后的VGA信息
return myInfo;
}
}
④.测试
package com.liu.test.adaptor.objectadaptor;
public class Test {
public static void main(String[] args) {
Projector adaptor = new Adaptor(new Computor());
String vgaInfo = adaptor.inputVGAInfo();//适配器将typec转换成vga
System.out.println("电脑输入HDMI信息已成功转换为VGA信息:" + vgaInfo);
}
}
3.接口适配器
当不想实现接口中的所有方法,只想实现自己需要的方法的时候使用
①. 电脑
package com.liu.test.adaptor.interfaceadaptor;
public interface IComputor {
String outputNum();
String outputStr();
}
②.转接头
package com.liu.test.adaptor.interfaceadaptor;
abstract class ComputorAdaptor implements IComputor{
public String outputNum(){
return "输出数字:1";
}
public String outputStr(){
return "输出字符串:hello";
}
}
③.测试
package com.liu.test.adaptor.interfaceadaptor;
public class Test {
public static void main(String[] args) {
ComputorAdaptor adaptor = new ComputorAdaptor() {
@Override
public String outputNum() {
return "适配后,输出数字:2";
}
};
System.out.println(adaptor.outputNum());
}
}
八、装饰器模式
装饰器模式又名包装(Wrapper)模式。装饰器模式动态地给一个对象添加一些额外的职责,以对客户端透明的方式拓展对象的功能,是继承关系的一种替代方案。一个简单的例子:一个开发人员,他应有的技能就是写代码;然后我们可以让他用java写代码也可以让他用C写代码,把java语言或者C语言赋予这个人,这就是装饰。
优点
- 可以对一个对象进行多次装饰,实现不同的组合,得到功能更多的对象。
- 被装饰者与装饰者都可以独立变化,用户可以根据需要自己增加新的装饰者和被装饰者。
缺点
- 产生很多小对象,一定程度上影响性能。
- 装饰模式调试排查麻烦。
示例:
1.创建被装饰者
package com.liu.test.designpattern.decorator;
public interface Developer {
String writeCode();
}
2.创建一个开发人员-我
package com.liu.test.designpattern.decorator.impl;
import com.liu.test.designpattern.decorator.Developer;
public class Me implements Developer {
@Override
public String writeCode() {
return "我写代码";
}
}
3.创建技能库
package com.liu.test.designpattern.decorator.impl;
import com.liu.test.designpattern.decorator.Developer;
abstract class Skills implements Developer {
Developer developer;
public Skills(Developer developer) {
this.developer = developer;
}
@Override
public String writeCode() {
return developer.writeCode();
}
}
4.创建各种技能
java:
package com.liu.test.designpattern.decorator.impl;
import com.liu.test.designpattern.decorator.Developer;
public class JavaSkill extends Skills{
public JavaSkill(Developer developer) {
super(developer);
}
@Override
public String writeCode() {
return super.writeCode() + ",使用java技术";
}
}
c语言:
package com.liu.test.designpattern.decorator.impl;
import com.liu.test.designpattern.decorator.Developer;
public class CSkill extends Skills{
public CSkill(Developer developer) {
super(developer);
}
@Override
public String writeCode() {
return super.writeCode() + ",使用C语言";
}
}
5.使用开发人员及其技能
package com.liu.test.designpattern.decorator;
import com.liu.test.designpattern.decorator.impl.CSkill;
import com.liu.test.designpattern.decorator.impl.JavaSkill;
import com.liu.test.designpattern.decorator.impl.Me;
public class Test {
public static void main(String[] args) {
//不赋予技能
Developer developer = new Me();
System.out.println(developer.writeCode());
//赋予java语言
developer = new JavaSkill(developer);
System.out.println(developer.writeCode());
//赋予C语言
developer = new CSkill(developer);
System.out.println(developer.writeCode());
}
}