java设计模式
2016-09-27 11:48
609 查看
一、设计模式的分类
创建型模式:
结构型模式:
行为型模式:
二、设计模式的六大原则
1、开闭原则
所谓开闭原则就是对扩展开放,对修改关闭。这样做是为了不修改原有代码,而又在原有代码的功能上实现新的功能,这就是为何要使用面向接口编程的原因。
2、里氏代换原则
任何基类可以出现的地方,子类一定可以出现。
3、依赖倒转原则
这是开闭原则的基础,直接对接口编程,依赖于接口,而不依赖于具体类。
4、接口隔离原则
使用多个隔离的接口比使用单个接口好。这个原则的目的就是降低耦合,降低依赖。
5、迪米特法则(最少知道原则)
一个实体最少的与其他实体发生相互关系,降低耦合。
6、合成复用原则
尽量使用合成/聚合方式,而不是使用继承。
三、设计模式详解
1、创建型模式
(1)单列模式
1)单列模式的作用:
确保某个类在整个系统中仅仅只有一个实例,并且类自动初始化这个实例。
2)单列模式的分类:
懒汉式单列模式:在第一次调用这个类的对象的时候进行实例化。
饿汉式单列模式:在类被调用的时候就已经初始化了对象。
3)饿汉式单列模式和懒汉式单列模式的区别:
懒汉式单列模式不是线程安全的,但是饿汉式单列模式是线程安全的。
懒汉式单列模式在第一次调用的时候比较慢,而饿汉式单列模式第一次调用的时候比懒汉式单列模式较快,但是后面应用的时候两者的速度就相等了。
注意:懒汉式单列模式依然可以实现线程安全,仅仅需要将获取对象的方法添加同步关键词。
4)单列模式的实例:
//懒汉式单列模式,在第一次调用的时候实例化自己
class Singleton1{
private Singleton1(){};
private static Singleton1 singleton1;
//静态工厂方法
public static Singleton1 getInstance(){
if (singleton1 == null) {
singleton1 = new Singleton1();
}
return singleton1;
}
}
//饿汗式单列模式 ,在类初始化的时候,已经自行实例化
class Singleton2{
private Singleton2(){};
private static final Singleton2 singleton2 = new Singleton2();
//静态工厂方法
public static Singleton2 getInstance(){
return singleton2;
}
}
(2)工厂模式
工厂模式分为工厂方法模式和抽象工厂模式。而简单工厂模式是工厂方法模式的一个特例。
1)简单工厂模式
简单工厂模式又称静态工厂方法模式。
针对抽象工厂方法模式,很好地实现了降低耦合。增加一个产品仅仅需要增加一个具体工厂即可。
2、结构型模式
(1)适配器模式
适配器模式的作用是将类的接口转换成客户端所需要的接口,目的是消除接口不匹配带来的兼容性问题。
适配器模式分为类适配器模式,对象适配器模式,接口适配器模式。
1)类适配器模式:
当一个类(源类)需要需要拥有另一个类(目标类)里面的功能的时候,可以创建一个新类(适配器类)来继承源类,并且实现目标类。
当需要一个类满足新接口的时候,可以创建一个新类实现这个接口,同时持有这个类的对象。
如果不想实现一个接口里面的所有方法,那么可以创建一个类实现该接口,然后让之前想要实现这个接口的类继承这个类,就可以实现部分方法了。
(2)组合模式
(3)装饰模式
装饰模式又叫做包装模式。装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。
1)装饰模式中的角色:
抽象构件角色:给出一个抽象接口,以规范准备接收附加责任的对象(定义装饰者和被装饰者的共有方法)。
具体构件角色:定义一个将要接收附加责任的类(被装饰者,实现抽象构件角色)。
抽象装饰角色:持有一个构件对象的实例,并定义一个与抽象构件一直的接口(持有构件对象,并在方法中调用构件对象的方法)。
具体装饰角色:负责给构件对象贴上附加的责任(继承抽象装饰角色,注意在构造器和方法中super的用法)。
(4)外观模式
适用于有多个子系统,但是不需要全部向用户展示,只需要用户知道使用这些子系统的途径。
要点:外观模式为复杂的子系统提供了一个简单的接口,并不为子系统添加新的功能和行为。
外观模式实现了子系统与客户之间的松散耦合。
外观模式注重的是简化接口。
(5)代理模式
1)代理模式的作用:为其他对象提供一种代理以控制对这个对象的访问。
2)代理模式中的角色:
抽象角色:定义代理对象和被代理对象的公共接口。
代理角色:代理角持有被代理角色,同时在代理角色的公共接口方法中调用了真实角色的方法,可以对真实角色的方法进行扩展。
真实角色:被代理对象,实现了抽象角色。
3)应用场景:对已有类功能的扩展,同时不将被代理类的信息显示给使用者。
4)应用实例:
3、行为型模式
(1)观察者模式
1)观察者模式的作用:观察者模式定义了一种一对多的对应关系,让多个观察者共同监听某一主题对象,当主题对象发生改变时,会通知所有观察者,从而观察者做出相应的改变。
2)观察者中的角色:
抽象主题角色:持有观察者,并且拥有对观察者进行增加、删除以及通知观察者的方法。
具体主题角色:继承抽象主题对象,并且添加了自己改变的方法,方法中调用通知观察者的方法。
抽象观察者角色:定义了自我更新的方法。
具体观察者角色:实现抽象观察者接口,并且实现了自我更新方法的具体内容。
3)观察者模式的分类:
推模型观察者模式:向观察者传入具体的参数,然后观察者根据需要作出相应的改变。
拉模型观察者模式:拉模型观察者模式通常是将自己传递给观察者,然后观察者按照需要获取主题对象的参数和,然后作出相应的改变。
3)观察者模式的应用场景:
当一个抽象模型的两个方面,其中一个方面依赖于另一个方面。将这两者封装在独立的对象中,使他们独自改变和维护。
当对一个对象的改变需要改变其他对象的时候,而又不知道有多少个对象需要改变。
当一个对象必须通知其他对象,而又不知道其他对象是谁。也就是不希望这些对象是紧密耦合。
4)观察者模式的应用实例:
(2)策略模式
1)策略模式的作用:
可以提供管理相关算法的算法簇的办法,并且可以将共有方法移到抽象类中。而且可以避免使用条件语句等多重循环。
2)策略模式中的角色:
环境角色:持有策略角色,并且调用相应的方法。
抽象策略角色:定义了策略接口,也就是策略类要实现什么功能。
具体策略角色:实现了抽象策略接口。
3)策略模式的应用场景:
4)策略模式的实例:
创建型模式:
结构型模式:
行为型模式:
二、设计模式的六大原则
1、开闭原则
所谓开闭原则就是对扩展开放,对修改关闭。这样做是为了不修改原有代码,而又在原有代码的功能上实现新的功能,这就是为何要使用面向接口编程的原因。
2、里氏代换原则
任何基类可以出现的地方,子类一定可以出现。
3、依赖倒转原则
这是开闭原则的基础,直接对接口编程,依赖于接口,而不依赖于具体类。
4、接口隔离原则
使用多个隔离的接口比使用单个接口好。这个原则的目的就是降低耦合,降低依赖。
5、迪米特法则(最少知道原则)
一个实体最少的与其他实体发生相互关系,降低耦合。
6、合成复用原则
尽量使用合成/聚合方式,而不是使用继承。
三、设计模式详解
1、创建型模式
(1)单列模式
1)单列模式的作用:
确保某个类在整个系统中仅仅只有一个实例,并且类自动初始化这个实例。
2)单列模式的分类:
懒汉式单列模式:在第一次调用这个类的对象的时候进行实例化。
饿汉式单列模式:在类被调用的时候就已经初始化了对象。
3)饿汉式单列模式和懒汉式单列模式的区别:
懒汉式单列模式不是线程安全的,但是饿汉式单列模式是线程安全的。
懒汉式单列模式在第一次调用的时候比较慢,而饿汉式单列模式第一次调用的时候比懒汉式单列模式较快,但是后面应用的时候两者的速度就相等了。
注意:懒汉式单列模式依然可以实现线程安全,仅仅需要将获取对象的方法添加同步关键词。
4)单列模式的实例:
//懒汉式单列模式,在第一次调用的时候实例化自己
class Singleton1{
private Singleton1(){};
private static Singleton1 singleton1;
//静态工厂方法
public static Singleton1 getInstance(){
if (singleton1 == null) {
singleton1 = new Singleton1();
}
return singleton1;
}
}
//饿汗式单列模式 ,在类初始化的时候,已经自行实例化
class Singleton2{
private Singleton2(){};
private static final Singleton2 singleton2 = new Singleton2();
//静态工厂方法
public static Singleton2 getInstance(){
return singleton2;
}
}
(2)工厂模式
工厂模式分为工厂方法模式和抽象工厂模式。而简单工厂模式是工厂方法模式的一个特例。
1)简单工厂模式
简单工厂模式又称静态工厂方法模式。
/** * 简单工厂方法模式 * @author LiuTao * */ //首先创建二者的共同接口,既抽象产品 interface Sender{ public void send(); } //创建两个具体产品,实现抽象产品 class SmsSender implements Sender{ @Override public void send() { System.out.println("send sms"); } } class EmailSender implements Sender{ @Override public void send() { System.out.println("send email"); } } //创建工厂类 class Factory{ public Sender product(String type){ switch (type) { case "sms": return new SmsSender(); case "email": return new EmailSender(); default: System.out.println("请输入正确的值"); return null; } } }2)多个工厂方法模式
/** * 多个工厂方法模式 * @author LiuTao * */ class SendFactory{ public Sender smsProduct(){ return new SmsSender(); } public Sender EmailProduct(){ return new EmailSender(); } }3)静态 工厂方法模式
/** * 静态工厂方法模式,将多个工厂方法模式的每个方法设置为静态的即可 * @author LiuTao * */ class StaticSendFactory{ public static Sender smsProduct(){ return new SmsSender(); } public static Sender emailProduct(){ return new EmailSender(); } }4)抽象工厂方法模式
针对抽象工厂方法模式,很好地实现了降低耦合。增加一个产品仅仅需要增加一个具体工厂即可。
/** * 抽象工厂模式,很好的遵守了开闭原则,如果增加了一个产品,则只需增加相应的具体产品工厂类,而不需要去修改工厂类 * @author LiuTao * */ //创建抽象工厂 interface AbstractFactory{ public Sender product(); } //创建两个具体工厂 class SmsFactory implements AbstractFactory{ @Override public Sender product() { return new SmsSender(); } } class EmailFactory implements AbstractFactory{ @Override public Sender product() { return new EmailSender(); } }
public class FactoryExample { public static void main(String[] args) { //测试简单工厂方法模式 Factory factory = new Factory(); Sender sender = factory.product("sms"); sender.send(); //测试多个工厂方法模式 SendFactory sendFactory = new SendFactory(); Sender sender2 = sendFactory.EmailProduct(); sender2.send(); //测试静态工厂方法模式 Sender sender3 = StaticSendFactory.smsProduct(); sender3.send(); //测试抽象工厂方法模式 AbstractFactory abstractFactory = new SmsFactory(); Sender sender4 = abstractFactory.product(); sender4.send(); } }
2、结构型模式
(1)适配器模式
适配器模式的作用是将类的接口转换成客户端所需要的接口,目的是消除接口不匹配带来的兼容性问题。
适配器模式分为类适配器模式,对象适配器模式,接口适配器模式。
1)类适配器模式:
当一个类(源类)需要需要拥有另一个类(目标类)里面的功能的时候,可以创建一个新类(适配器类)来继承源类,并且实现目标类。
/** * 类的适配器模式 * @author LiuTao * */ //创建待适配的类 class Source{ public void method1(){ System.out.println("this is orginal method"); } } //创建目标接口 interface Target{ public void method1(); public void method2(); } //创建适配器 class Adapter extends Source implements Target{ @Override public void method2() { System.out.println("this is target method"); } }2)对象适配器
当需要一个类满足新接口的时候,可以创建一个新类实现这个接口,同时持有这个类的对象。
/** * 对象适配器模式 * @author LiuTao * */ class Wrapper implements Target{ private Source source; public Wrapper(Source source) { super(); this.source = source; } @Override public void method1() { source.method1(); } @Override public void method2() { System.out.println("this is target method"); } }3)接口的适配器模式
如果不想实现一个接口里面的所有方法,那么可以创建一个类实现该接口,然后让之前想要实现这个接口的类继承这个类,就可以实现部分方法了。
/** * 对象适配器模式 * @author LiuTao * */ class Wrapper implements Target{ private Source source; public Wrapper(Source source) { super(); this.source = source; } @Override public void method1() { source.method1(); } @Override public void method2() { System.out.println("this is target method"); } }
public class AdapterExample { public static void main(String[] args) { //测试类的适配器模式 Target target = new Adapter(); target.method1(); target.method2(); //测试对象适配器模式 Source source = new Source(); Target target2 = new Wrapper(source); target2.method1(); target2.method2(); //测试接口适配器模式 Sourceable sourceable1 = new SourceSub1(); Sourceable sourceable2 = new SourceSub2(); sourceable1.method1(); sourceable1.method2(); sourceable2.method1(); sourceable2.method2(); } }
(2)组合模式
(3)装饰模式
装饰模式又叫做包装模式。装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。
1)装饰模式中的角色:
抽象构件角色:给出一个抽象接口,以规范准备接收附加责任的对象(定义装饰者和被装饰者的共有方法)。
具体构件角色:定义一个将要接收附加责任的类(被装饰者,实现抽象构件角色)。
抽象装饰角色:持有一个构件对象的实例,并定义一个与抽象构件一直的接口(持有构件对象,并在方法中调用构件对象的方法)。
具体装饰角色:负责给构件对象贴上附加的责任(继承抽象装饰角色,注意在构造器和方法中super的用法)。
public class DecoratorExample { public static void main(String[] args) { TheGreatestSage sage = new Monkey(); // 第一种写法 TheGreatestSage bird = new Bird(sage); TheGreatestSage fish = new Fish(bird); // 第二种写法 //TheGreatestSage fish = new Fish(new Bird(sage)); fish.move(); } } //抽象构件角色 interface TheGreatestSage{ public void move(); } //具体构件角色 class Monkey implements TheGreatestSage{ @Override public void move() { System.out.println("Monkey Move"); } } //抽象装饰角色 class Change implements TheGreatestSage{ private TheGreatestSage sage; public Change(TheGreatestSage sage) { this.sage = sage; } @Override public void move() { sage.move(); } } //具体装饰角色 class Fish extends Change{ public Fish(TheGreatestSage sage) { super(sage); } @Override public void move() { super.move(); System.out.println("Fish Move"); } } //具体装饰角色 class Bird extends Change{ public Bird(TheGreatestSage sage) { super(sage); } @Override public void move() { super.move(); System.out.println("Bird Move"); } }
(4)外观模式
适用于有多个子系统,但是不需要全部向用户展示,只需要用户知道使用这些子系统的途径。
要点:外观模式为复杂的子系统提供了一个简单的接口,并不为子系统添加新的功能和行为。
外观模式实现了子系统与客户之间的松散耦合。
外观模式注重的是简化接口。
public class FacaderExample { public static void main(String[] args) { //测试外观模式 Computer computer = new Computer(); computer.startUp(); } } //创建子系统角色 class CPU{ public void startUp(){ System.out.println("CPU start up"); } } class Memory{ public void startUp(){ System.out.println("Memory start up"); } } class Disk{ public void startUp(){ System.out.println("Disk start up"); } } //创建门面角色 class Computer{ private CPU cpu; private Memory memory; private Disk disk ; public Computer() { cpu = new CPU(); memory = new Memory(); disk = new Disk(); } public void startUp() { cpu.startUp(); memory.startUp(); disk.startUp(); } }
(5)代理模式
1)代理模式的作用:为其他对象提供一种代理以控制对这个对象的访问。
2)代理模式中的角色:
抽象角色:定义代理对象和被代理对象的公共接口。
代理角色:代理角持有被代理角色,同时在代理角色的公共接口方法中调用了真实角色的方法,可以对真实角色的方法进行扩展。
真实角色:被代理对象,实现了抽象角色。
3)应用场景:对已有类功能的扩展,同时不将被代理类的信息显示给使用者。
4)应用实例:
public class ProxyExample { public static void main(String[] args) { //测试代理模式 Sourceable source = new Proxy(); source.method(); } } //创建公共接口 interface Sourceable{ public void method(); } //创建被代理类 class Source implements Sourceable{ @Override public void method() { System.out.println("the orginal method"); } } //创建代理类 class Proxy implements Sourceable{ private Sourceable source; public Proxy() { super(); source = new Source(); } @Override public void method() { beforeProxy(); source.method(); afterProxy(); } public void beforeProxy(){ System.out.println("before proxy"); } public void afterProxy(){ System.out.println("after proxy"); } }
3、行为型模式
(1)观察者模式
1)观察者模式的作用:观察者模式定义了一种一对多的对应关系,让多个观察者共同监听某一主题对象,当主题对象发生改变时,会通知所有观察者,从而观察者做出相应的改变。
2)观察者中的角色:
抽象主题角色:持有观察者,并且拥有对观察者进行增加、删除以及通知观察者的方法。
具体主题角色:继承抽象主题对象,并且添加了自己改变的方法,方法中调用通知观察者的方法。
抽象观察者角色:定义了自我更新的方法。
具体观察者角色:实现抽象观察者接口,并且实现了自我更新方法的具体内容。
3)观察者模式的分类:
推模型观察者模式:向观察者传入具体的参数,然后观察者根据需要作出相应的改变。
拉模型观察者模式:拉模型观察者模式通常是将自己传递给观察者,然后观察者按照需要获取主题对象的参数和,然后作出相应的改变。
3)观察者模式的应用场景:
当一个抽象模型的两个方面,其中一个方面依赖于另一个方面。将这两者封装在独立的对象中,使他们独自改变和维护。
当对一个对象的改变需要改变其他对象的时候,而又不知道有多少个对象需要改变。
当一个对象必须通知其他对象,而又不知道其他对象是谁。也就是不希望这些对象是紧密耦合。
4)观察者模式的应用实例:
public class ObserverExample { public static void main(String[] args) { //创建主题对象 ConcreteSubject concreteSubject = new ConcreteSubject(); //创建观察者对象 Observer observer = new ConcreteObserver(); //将观察者对象添加到主题对象 concreteSubject.attach(observer); //改变主题对象角色 concreteSubject.change("new state"); } } /** *推模型观察者模式 */ //抽象主题角色 abstract class Subject{ //用来保存注册的观察者对象 private List<Observer> list = new ArrayList<Observer>(); //注册观察者对象 public void attach(Observer observer){ list.add(observer); System.out.println("Attached an observer"); } //删除观察者对象 public void remove(Observer observer){ list.remove(observer); System.out.println("Remove an observer"); } //通知所有注册的观察者对象 public void nodifyObservers(String newState){ for (Observer observer : list) { observer.update(newState); } } } //具体主题角色 class ConcreteSubject extends Subject{ private String state; public String getState(){ return state; } public void change(String newState){ state = newState ; System.out.println("主题状态为:"+state); //状态发生改变,通知各个观察者 this.nodifyObservers(state); } } //抽象观察者角色 interface Observer{ public void update(String state); } //具体观察者角色 class ConcreteObserver implements Observer{ //观察者的状态 private String observerState; @Override public void update(String state) { //更新观察者的状态,使其与目标的状态保持一致 observerState = state; System.out.println("状态为:"+observerState); } } /** *拉模型观察者模式 */ //抽象观察者 interface Observer1{ //更新接口,之前传入的是具体的参数,现在传入主题对象,又观察者自己按需获取想要的参数。 public void update(Subject subject); } //具体观察者 class ConcreteObserver1 implements Observer1{ private String observerState; @Override public void update(Subject subject) { observerState = ((ConcreteSubject)subject).getState(); System.out.println("观察者状态为:"+observerState); } }
(2)策略模式
1)策略模式的作用:
可以提供管理相关算法的算法簇的办法,并且可以将共有方法移到抽象类中。而且可以避免使用条件语句等多重循环。
2)策略模式中的角色:
环境角色:持有策略角色,并且调用相应的方法。
抽象策略角色:定义了策略接口,也就是策略类要实现什么功能。
具体策略角色:实现了抽象策略接口。
3)策略模式的应用场景:
4)策略模式的实例:
public class StrategyExample { public static void main(String[] args) { //测试策略模式 Price price = new Price(new AdvancedMemberStrategy()); System.out.println("计算后的价格是:"+price.quote(12.12)); } } //创建抽象策略角色 interface MemberStrategy { public double calPrice(double booksPrice); } //创建具体策略角色 class PrimaryMemberStrategy implements MemberStrategy{ @Override public double calPrice(double booksPrice) { return booksPrice; } } class IntermediateMemberStrategy implements MemberStrategy{ @Override public double calPrice(double booksPrice) { return booksPrice*0.9; } } class AdvancedMemberStrategy implements MemberStrategy{ @Override public double calPrice(double booksPrice) { return booksPrice*0.8; } } //创建环境角色 class Price{ MemberStrategy memberStrategy; public Price(MemberStrategy memberStrategy) { this.memberStrategy = memberStrategy; } public double quote(double bookPrice){ return this.memberStrategy.calPrice(bookPrice); } }
相关文章推荐
- Spring boot 基础
- JDK1.7 Collections.sort排序异常
- Spring Security4.1.3实现拦截登录后向登录页面跳转方式(redirect或forward)返回被拦截界面
- java基础50题(4)
- Java高新技术——内省(JavaBean)
- java中异常抛出后代码还会继续执行吗
- 拆 RxJava
- 【Spring】——IOC原理
- java编程中static关键字
- 策略模式的java实现例子
- javascirpt用享元模式实现日历
- 在 eclipse 中 设置 jvm 的 运行时目录
- Spring的切面 AOP
- LeetCode 第十四题 Longest Common Prefix(最长公共前缀)
- jarsigner 错误: java.lang.RuntimeException: 密钥库加载: Invalid keystore format
- 《java编程思想》第五章:初始化和清理
- JVM学习笔记(二)——xms&&xmx
- JSP 入门 HTML嵌套Java脚步 显示时间
- java.text.NumberFormat用法
- Java中static的简单解析