原文链接:https://blog.csdn.net/jason0539/article/details/23297037
设计模式的优点
设计模式可在多个项目中重用。
设计模式提供了一个帮助定义系统架构的解决方案。
设计模式吸收了软件工程的经验。
设计模式为应用程序的设计提供了透明性。
设计模式是被实践证明切实有效的,由于它们是建立在专家软件开发人员的知识和经验之上的。
单例模式
单例模式的写法有好几种,这里主要介绍三种:懒汉式单例、饿汉式单例
单例模式有以下特点:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
总之,选择单例模式就是为了避免不一致状态,避免政出多头。
一、懒汉式单例
//懒汉式单例类.在第一次调用的时候实例化自己
public class Singleton {
private Singleton() {}
private static Singleton single=null;
//静态工厂方法
public static Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
}
Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问。
实现线程安全:
线程安全一:
在getInstace方法上加同步
方法调用上加了同步,虽然线程安全了,但是每次都要同步,
会影响性能,毕竟99%的情况下是不需要同步的
public static synchronized Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
线程安全二:
线程安全二:双重检查锁定
在getInstance中做了两次null检查,
确保了只有第一次调用单例的时候才会做同步,
这样也是线程安全的,同时避免了每次都同步的性能损耗
public static Singleton getInstance() {
if (single == null) {
synchronized (Singleton.class) {
if (single == null) {
single = new Singleton();
}
}
}
return singleton;
}
线程安全三:
静态内部类
既实现线程安全又避免同步带来的影响
利用了classloader的机制来保证初始化instance时只有一个线程
public class Singleton {
private static class LazyHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}
二、饿汉式单例
final:保证天生线程安全
//饿汉式单例类.在类初始化时,已经自行实例化
public class Singleton1 {
private Singleton1() {}
private static final Singleton1 single = new Singleton1();
//静态工厂方法
public static Singleton1 getInstance() {
return single;
}
}
工厂模式
介绍:
1)还没有工厂时代:假如还没有工业革命,如果一个客户要一款宝马车,一般的做法是客户去创建一款宝马车,然后拿来用。
2)简单工厂模式:后来出现工业革命。用户不用去创建宝马车。因为客户有一个工厂来帮他创建宝马.想要什么车,这个工厂就可以建。比如想要320i系列车。工厂就创建这个系列的车。即工厂可以创建产品。
3)工厂方法模式时代:为了满足客户,宝马车系列越来越多,如320i,523i,30li等系列一个工厂无法创建所有的宝马系列。于是由单独分出来多个具体的工厂。每个具体工厂创建一种系列。即具体工厂类只能创建一个具体产品。但是宝马工厂还是个抽象。你需要指定某个具体的工厂才能生产车出来。
4)抽象工厂模式时代:随着客户的要求越来越高,宝马车必须配置空调。于是这个工厂开始生产宝马车和需要的空调。
最终是客户只要对宝马的销售员说:我要523i空调车,销售员就直接给他523i空调车了。而不用自己去创建523i空调车宝马车.
分类:
1)简单工厂模式(Simple Factory)
2)工厂方法模式(Factory Method)
3)抽象工厂模式(Abstract Factory)
这三种模式从上到下逐步抽象,并且更具一般性。
也可以 将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。
分别:工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory)。
工厂方法模式:
一个抽象产品类,可以派生出多个具体产品类。
一个抽象工厂类,可以派生出多个具体工厂类。
每个具体工厂类只能创建一个具体产品类的实例。
抽象工厂模式:
多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。
一个抽象工厂类,可以派生出多个具体工厂类。
每个具体工厂类可以创建多个具体产品类的实例。
区别:
工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。
工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。
两者皆可。
简单工厂模式
产品类:
abstract class BMW {
public BMW(){
}
}
public class BMW320 extends BMW {
public BMW320() {
System.out.println("制造-->BMW320");
}
}
public class BMW523 extends BMW{
public BMW523(){
System.out.println("制造-->BMW523");
}
}
工厂类:
public class Factory {
public BMW createBMW(int type) {
switch (type) {
case 320:
return new BMW320();
case 523:
return new BMW523();
default:
break;
}
return null;
}
}
客户类:
public class Customer {
public static void main(String[] args) {
Factory factory = new Factory();
BMW bmw320 = factory.createBMW(320);
BMW bmw523 = factory.createBMW(523);
}
}
工厂方法模式
工厂方法模式去掉了简单工厂模式中工厂方法的静态属性,使得它可以被子类继承。这样在简单工厂模式里集中在工厂方法上的压力可以由工厂方法模式里不同的工厂子类来分担。
工厂方法模式组成:
1)抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
2)具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。
3)抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。
4)具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。
工厂方法模式使用继承自抽象工厂角色的多个子类来代替简单工厂模式中的“上帝类”。正如上面所说,这样便分担了对象承受的压力;而且这样使得结构变得灵活 起来——当有新的产品产生时,只要按照抽象产品角色、抽象工厂角色提供的合同来生成,那么就可以被客户使用,而不必去修改任何已有 的代码。
产品类:
abstract class BMW {
public BMW(){
}
}
public class BMW320 extends BMW {
public BMW320() {
System.out.println("制造-->BMW320");
}
}
public class BMW523 extends BMW{
public BMW523(){
System.out.println("制造-->BMW523");
}
}
创建工厂类:
interface FactoryBMW {
BMW createBMW();
}
public class FactoryBMW320 implements FactoryBMW{
@Override
public BMW320 createBMW() {
return new BMW320();
}
}
public class FactoryBMW523 implements FactoryBMW {
@Override
public BMW523 createBMW() {
return new BMW523();
}
}
客户类:
public class Customer {
public static void main(String[] args) {
FactoryBMW320 factoryBMW320 = new FactoryBMW320();
BMW320 bmw320 = factoryBMW320.createBMW();
FactoryBMW523 factoryBMW523 = new FactoryBMW523();
BMW523 bmw523 = factoryBMW523.createBMW();
}
}
抽象工厂模式
抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。比如宝马320系列使用空调型号A和发动机型号A,而宝马230系列使用空调型号B和发动机型号B,那么使用抽象工厂模式,在为320系列生产相关配件时,就无需制定配件的型号,它会自动根据车型生产对应的配件型号A。
产品类:
//发动机以及型号
public interface Engine {
}
public class EngineA extends Engine{
public EngineA(){
System.out.println("制造-->EngineA");
}
}
public class EngineBextends Engine{
public EngineB(){
System.out.println("制造-->EngineB");
}
}
//空调以及型号
public interface Aircondition {
}
public class AirconditionA extends Aircondition{
public AirconditionA(){
System.out.println("制造-->AirconditionA");
}
}
public class AirconditionB extends Aircondition{
public AirconditionB(){
System.out.println("制造-->AirconditionB");
}
}
创建工厂类:
//创建工厂的接口
public interface AbstractFactory {
//制造发动机
public Engine createEngine();
//制造空调
public Aircondition createAircondition();
}
//为宝马320系列生产配件
public class FactoryBMW320 implements AbstractFactory{
@Override
public Engine createEngine() {
return new EngineA();
}
@Override
public Aircondition createAircondition() {
return new AirconditionA();
}
}
//宝马523系列
public class FactoryBMW523 implements AbstractFactory {
@Override
public Engine createEngine() {
return new EngineB();
}
@Override
public Aircondition createAircondition() {
return new AirconditionB();
}
}
客户:
public class Customer {
public static void main(String[] args){
//生产宝马320系列配件
FactoryBMW320 factoryBMW320 = new FactoryBMW320();
factoryBMW320.createEngine();
factoryBMW320.createAircondition();
//生产宝马523系列配件
FactoryBMW523 factoryBMW523 = new FactoryBMW523();
factoryBMW320.createEngine();
factoryBMW320.createAircondition();
}
}
设计模式面试总结:
Singleton(单例模式)
一句话总结:一个类在Java虚拟机中只有一个对象,并提供一个全局访问点。
生活中例子:太阳、月亮、国家主席等。
解决什么问题:对象的唯一性,性能浪费太多。
项目里面怎么用:数据库连接对象,属性配置文件的读取对象。
模式结构:分为饿汉式和懒汉式(如果考虑性能问题的话,就使用懒汉式,因为懒汉式是在方法里面进行初始化的),构造器私 有化,对外提供方法加同步关键字。
框架里面使用:Struts1的Action。
JDK里面使用:java.lang.Runtime#getRuntimejava.awt.Desktop#getDesktop。
Factory(简单的工厂模式)
一句话总结:用一个方法来代替new关键字
生活中的例子:制衣厂、面包厂等生产厂。
解决什么问题:对象产生过多,或者经常有子类替换生成。
项目里面怎么用:对于经常生成的对象,或者父子类替换的对象。
模式结构:写一个对外声明的方法,方法里面使用new关键字代替。
框架里面使用:spring的核心就是工厂模式。
JDK里面使用:newInstance。
Proxy(代理模式)
一句话总结:为其他对象提供一个代理,以控制对当前对象的访问。
生活中的例子:房屋中介、婚姻介绍所。
解决什么问题:不能直接访问该对象,或者太大的资源耗费多。
项目里面怎么用:权限,或者大对象的访问权限。
模式结构:代理类和被代理类实现同一个接口,用户访问的时候先访问代理对象,然后让代理对象去访问被代理对象。
框架里面使用:Spring里面的AOP实现。
JDK里面使用:java.lang.reflect.Proxy。
创建一个接口:
public interface SellHouse {
void sell(double money);
}
创建一个被代理类:
public class Hoster implements SellHouse {
@Override
public void sell(double money) {
System.out.println("祝你居住愉快");
}
}
创建一个代理类:
public class Medium implements SellHouse {
SellHouse hoster=new Hoster();
@Override
public void sell(double money) {
if(money>=1000){
hoster.sell(money);
}else{
System.out.println("你的价格太低了");
}
}
}
测试类:
public class Renter {
public static void main(String[] args) {
SellHouse renter=new Medium();
renter.sell(500);
}
}
Adapter(适配器模式)
一句话总结:将两个原来不兼容的类兼容起来一起工作。
生活中的例子:变压器、充电器
解决什么问题:已经存在的相同功能的代码,但是接口不兼容,不能直接调用。
项目里面怎么用:在使用旧的API的时候,没有源码,和新的不能兼容。
模式结构:分为类适配器和对象适配,一般常用的就是对象适配器,因为组合由于继承。
框架里面使用:单元测试里面的asserEquels。
JDK里面使用:java.util.Arrays#asListjava.io.InputStreamReader(InputStream) java.io.outputStreamWriter(OutputStream)。
Strategy(策略模式)
一句话总结:定义一系列算法并可以互相替换。
生活中的例子:图片的格式,压缩文件的格式。
解决什么问题:做一件事情有很多种方法。
项目里面怎么用:购物车里面的付款方式。
模式结构:声明一个顶级接口,定义一个策略方法,具体的实例都要实现这个接口。
框架里面使用:hibernate的主键生成策略。
JDK里面使用:java.util.Comparator#compare。
定义一个顶级接口:
public interface Person {
void repast();
}
具体实例类1
public class African implements Person {
@Override
public void repast() {
System.out.println("非洲人用手吃饭");
}
}
具体实例类2
public class America implements Person {
@Override
public void repast() {
System.out.println("美国人用刀叉吃饭");
}
}
具体实例类3
public class Chinese implements Person {
@Override
public void repast() {
System.out.println("中国人用筷子吃饭");
}
}
测试类:
public class Test {
public static void main(String[] args) {
Person chinese=new Chinese();
Person america=new America();
Person african=new African();
chinese.repast();
america.repast();
african.repast();
}
}
Template(模板模式)
一句话总结:父类定义流程,子类实现流程。
生活中的例子:iphone生产有多个国家,但流程只有一个。
解决什么问题:业务有多种,但都有规定的流程。
项目里面怎么用:一般基类的实现都是模板模式,BaseDAO,bBaseService。
模式结构:定义一个抽象父类定义流程,或者常用方法和常量,子类继承父类,实现具体的细节方法。
框架里面使用:hibernate里面的方言,是跨数据库的基础。
JDK里面使用:IO流里面的InputStream,Writer等。
模板模式代码:
//定义一个父类,定义流程
public abstract class IPhoneTemplate {
public void createIPhone(){
setupCpu();
setupAll();
check();
box();
}
protected abstract void box();
protected abstract boolean check();
protected abstract void setupAll();
protected abstract void setupCpu();
}
子类实现父类的细节方法1
public class ChinaIPhone extends IPhoneTemplate {
@Override
protected void box() {
System.out.println("box()");
}
@Override
protected boolean check() {
System.out.println("check()");
return true;
}
@Override
protected void setupAll() {
System.out.println("setupAll()");
}
@Override
protected void setupCpu() {
System.out.println("setupCpu()");
}
}
子类实现父类的细节方法2
public class AfricanIPhone extends IPhoneTemplate {
@Override
protected void box() {
System.out.println("box()");
}
@Override
protected boolean check() {
System.out.println("check()");
return true;
}
@Override
protected void setupAll() {
System.out.println("setupAll()");
}
@Override
protected void setupCpu() {
System.out.println("setupCpu()");
}
}