1.概述
设计模式最早是出现在建筑领域,1977年,美国著名建筑大师、加利福尼亚大学伯克利分校环境结构中心主任克里斯托夫·亚历山大在他的著作《建筑模式语言:城镇、建筑、构造中描述了一些常见的建筑设计问题,并提出了 253 种关于对城镇、邻里、住宅、花园和房间等进行设计的基本模式。到1990年,软件设计界才开始讨论软件的设计模式,1995年,美国的4位作者共同编著了《设计模式:可复用面向对象软件的基础》,这本书中收录了23中设计模式,设计模式的设计是对面向对象的原则的实际应用,对类的继承,封装及多态的综合应用。设计模式按照其功能可分为创建型,结构型及行为型。
- 创建型:将对象的创建和使用分离。主要有单例模式,原型,工厂方法、抽象工厂和建造者模式。
- 结构型:通过类的之间的关系组织成更大的结构。主要有代理、适配器、桥接、装饰、外观、享元、组合模式。
- 行为型:主要类或对象之间怎么通过相互协作完成单个对象无法完成的功能,以及分配职责。主要有模板方法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录、解释器模式。
2.单例模式
单例模式:一个类通过将构造方法私有,暴露出获取对象的方法,使该类仅仅能够创建一个对象。具体实现方式有懒汉式、饿汉式、枚举方式,懒汉式:比较懒,在调用获取单例对象的时候才去创建类的对象,饿汉式:在类在类加载系统中加载后就被创建了,当调用获取单例对象方法的时候直接获取。
- 饿汉式
public class HungrySingleton {
private HungrySingleton(){} //将构造方法私有化,防止别的类实例化该类
private static final HungrySingleton INSTANCE = new HungrySingleton();
//创建饿汉式类的对象,并且实例化,该对象会在类加载链接准备阶段置为null,在初始化阶段分配具体的对象
private static HungrySingleton getInstance(){ //获取饿汉式类的对象 HungrySingleton.getInstance();
return INSTANCE;
}
}
- 懒汉式
public class LazySingleton {
private LazySingleton(){} //构造方法私有化
private static volatile LazySingleton instance = null; //volatile保证线程缓存失效,访问主存
public static LazySingleton getInstance(){
if (null == instance){ //首先判断instance如果为null的话就进入new 对象逻辑,如果不为null,则直接返回实例
synchronized (LazySingleton.class){ //抢锁
if (null == instance){
//此再次判断instance是否为null,防止,多个线程进入强锁环节,一个线程获取了锁,创建了对象
//然后别的线程获取到了锁然后又重新创建了一次,导致对象重复
//加了判断后,即使抢到了锁,仍然判断是否为null,就解决了这个问题。
instance = new LazySingleton();
}
}
}
return instance;
}
}
应用场景
常被创建而又被销毁:一个类创建多个对象后需要被垃圾收集器清理,如果一个类经常被创建而后被回收,就考虑使用单例模式,这样可以节省内存。如数据库连接池。
生活例子:一个班只有一个班长,一个村只有一个村长,一个省只有一个省长,在java中对这些只有一个对象进行初始化并且赋值的时候,如果生成了多个对象就会导致一个班里可能存在多个班长的情况。
2.工厂模式
工厂模式:包含简单工厂模式,工厂方法模式,抽象工厂模式。
- 简单工程模式
定义一个工厂类,传入字符串,工厂方法中通过字符串判断应该创建什么类,然后返回对象。使用案例:一个大型xml文件中,如果直接映射为一个java类对象可能比较复杂,可以通过将xml文件依据节点信息进行分割成不同部分,然后解析不同的节点,而不同节点对应的java对象的生成就可以使用简单工厂方法,依据节点的名称传入到简单工厂方法中,然后返回java类对象,然后将节点解析出来的数据保存到java对象中,然后将java对象作为entity保存到数据库中。 -
工厂方法模式:
通过创建工厂接口,工厂接口中定义返回具体功能的方法,不同的工厂实现工厂接口。在各种框架中,经常使用工厂方法模式,通过工厂类来获取目标类。interface IProduct{ void function(); } class Car implements IProduct{ @Override public void function() { System.out.println("载人"); } } class MP3 implements IProduct{ @Override public void function() { System.out.println("听音乐"); } } interface IFactory{ IProduct newProduct(); } class MusicFactory implements IFactory{ @Override public IProduct newProduct() { return new MP3(); } } class CarFactory implements IFactory{ @Override public IProduct newProduct() { return new Car(); } }
-
抽象工厂模式
抽象工程模式仍然定义工厂接口,但接口中定义多个方法,方法返回不同的产品,达到一个工厂能够生产多个产品的功能。interface IProduct{ void function(); } class Car implements IProduct{ @Override public void function() { System.out.println("载人"); } } class MP3 implements IProduct{ @Override public void function() { System.out.println("听音乐"); } } interface IPlant{ void function(); } class Apple implements IPlant{ @Override public void function() { System.out.println("补充维c,远离医生"); } } class Peanut implements IPlant{ @Override public void function() { System.out.println("吃花生"); } } interface IFactory{ IProduct newProduct(); IPlant newPlant(); } class SHCityFactory implements IFactory{ @Override public IProduct newProduct() { return new MP3(); } @Override public IPlant newPlant() { return new Apple(); } } class BGCityFactory implements IFactory{ @Override public IProduct newProduct() { return new Car(); } @Override public IPlant newPlant() { return new Peanut(); } }
生活例子:一个城市有多个工厂,有饮料厂,电器厂,手机厂等等,而客户有多种需求,有的想要苹果汁和耳机、有的想要iphone手机和空调等等,通过向工厂发出指令得到不同的产品。
3.建设者模式
当创建一个复杂的对象的时候,并且该对象有多个组件组成,例如一个人由多种器官组成,如鼻子,头发,眉毛,皮肤,手,胳膊,腿等等。建设者模式主要由产品、建设者和指挥者三个角色组成。建设者中定义产品组件具体的定义方法,在指挥者中,传入具体的建设者,并且调用建设者的具体建设方法,返回建设者中的产品对象。
class Good{
String partA;
String partB;
String partC;
String partD;
public String getPartA() {
return partA;
}
public void setPartA(String partA) {
this.partA = partA;
}
public String getPartB() {
return partB;
}
public void setPartB(String partB) {
this.partB = partB;
}
public String getPartC() {
return partC;
}
public void setPartC(String partC) {
this.partC = partC;
}
public String getPartD() {
return partD;
}
public void setPartD(String partD) {
this.partD = partD;
}
}
abstract class GoodBuilder{
protected Good good = new Good();
abstract void setGoodPartA();
abstract void setGoodPartB();
abstract void setGoodPartC();
abstract void setGoodPartD();
public Good getGood(){
return this.good;
}
}
class DesktopBuilder extends GoodBuilder{
@Override
void setGoodPartA() {
super.good.setPartA("desktop-parta");
}
@Override
void setGoodPartB() {
super.good.setPartB("desktop-partb");
}
@Override
void setGoodPartC() {
super.good.setPartC("desktop-partc");
}
@Override
void setGoodPartD() {
super.good.setPartD("desktop-partd");
}
}
class Diretor{
private GoodBuilder builder;
public Diretor(GoodBuilder builder){
this.builder = builder;
builder.setGoodPartA();
builder.setGoodPartB();
builder.setGoodPartC();
builder.setGoodPartD();
}
public Good getGood(){
return builder.getGood();
}
}
class Client {
public static void main(String[] args) {
GoodBuilder goodBuilder = new DesktopBuilder();
Diretor diretor = new Diretor(goodBuilder);
Good good = goodBuilder.getGood();
System.out.println(good.getPartA());
}
}
3.代理模式
代理模式:访问一个对象不是直接访问该对象,而是访问该对象的代理对象,代理对象然后再访问真正的对象。此种操作,能够对访问对象作出限制、增强或者修改等操作。
- 静态代理
public class StaticProxy {
public static void main(String[] args) {
Telephone realTelephone = new RealTelephone();
Telephone proxy = new ProxyTelephone(realTelephone);
proxy.call();
}
}
interface Telephone{
void call();
}
class RealTelephone implements Telephone{
@Override
public void call() {
System.out.println("打电话啦");
}
}
class ProxyTelephone implements Telephone{
private Telephone telephone;
public ProxyTelephone(Telephone telephone){
this.telephone = telephone;
}
@Override
public void call() {
this.preCall();
telephone.call();
this.afterCall();
}
private void preCall(){
System.out.println("打电话之前");
}
private void afterCall(){
System.out.println("打电话之后");
}
}
- 动态代理(jdk)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxy {
public static void main(String[] args) {
StoreOneSellWine storeOneSellWine = new StoreOneSellWine();
InvocationHandler superMarket = new SuperMarket(storeOneSellWine);
SellWine proxySellWine = (SellWine) Proxy.newProxyInstance(StoreOneSellWine.class.getClassLoader(), StoreOneSellWine.class.getInterfaces(), superMarket);
proxySellWine.sell();
}
}
interface SellWine{
void sell();
}
class StoreOneSellWine implements SellWine{
@Override
public void sell() {
System.out.println("商家1卖酒");
}
}
class SuperMarket implements InvocationHandler {
private Object proxyedClassObject;
public SuperMarket(Object proxyedClassObject){
this.proxyedClassObject = proxyedClassObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
this.preCall();
Object result = method.invoke(proxyedClassObject, args);
this.afterCall();
return result;
}
private void preCall(){
System.out.println("动态代理调用之前");
}
private void afterCall(){
System.out.println("动态代理调用之后");
}
}
jdk动态代理源码分析
SellWine proxySellWine = (SellWine) Proxy.newProxyInstance(StoreOneSellWine.class.getClassLoader(), StoreOneSellWine.class.getInterfaces(), superMarket);
--------------------------------------------------------
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
//获取StoreOneSellWine.class.getInterfaces()接口的所有类
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);
//返回包含StoreOneSellWine.class.getInterfaces()所有接口的class对象
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor<?> cons = cl.getConstructor(constructorParams);
//通过class对象得到构造器
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
return cons.newInstance(new Object[]{h});
//通过构造器创建新的对象,h为superMarket,实现invocationHandler接口的类
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
----------------------------------------------
通过SellWine具体实现类,获取该实现类的所有实现的接口信息,然后依据这些接口信息生成特殊的字节码byte[],这个生成方法在ProxyClassFactory类中实现的。
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
//proxyName 为包名+$Proxy+生成的序号,包名为生成动态代理对象所在的包名
/*
* Generate the specified proxy class.
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags); //生成byte[]
try {
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);//调用native方法,得到class对象
生活例子:我要买生活用品,而生活用品是商家生产的,我要购买到,需要到商家指定的超市进行购买,我要买的东西,超市已经给我买好了,这个超市就是我买东西的代理商。
4.模版模式
当解决某一个问题方法步骤基本上是固定,如工作日一天的基本流程:起床,刷牙,吃饭,坐公交,工作,吃午饭,午休,工作,坐公交,吃饭,睡觉。这个流程中工作的内容会不断的变化,那么就可以定义一个模版类,包含这些基本的流程,并且有一定的实现,当子类需要变化时,再进行具体的实现。
public interface WorkDayInterface {
void toWork();
void eatFood();
void morningWork();
void rest();
void afternoonWork();
void goHome();
}
abstract class WorkDay implements WorkDayInterface{
public void toWork(){
System.out.println("坐地铁");
}
public void eatFood(){
System.out.println("喝牛奶");
}
public abstract void morningWork();
public void rest(){
System.out.println("午睡");
}
public abstract void afternoonWork();
public void goHome(){
System.out.println("坐地铁");
}
}
class Monday extends WorkDay{
@Override
public void morningWork() {
System.out.println("调试代码");
}
@Override
public void afternoonWork() {
System.out.println("调试代码");
}
}
class Tuesday extends WorkDay{
@Override
public void morningWork() {
System.out.println("编码xx模块");
}
@Override
public void afternoonWork() {
System.out.println("编码xx模块");
}
}
5.设计模式的七大原则
- 单一职责原则
- 接口隔离原则
- 依赖倒转原则
----- 接口 - 里斯替换原则
- 合成复用原则
----- 继承 - 开闭原则
- 迪米特法则
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。