一、责任链模式
概念:为了避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
优点:
- 降低了对象之间的耦合度。该模式使得一个对象无须知道到底是哪一个对象处理其请求以及链的结构,发送者和接收者也无须拥有对方的明确信息。
- 增强了系统的可扩展性。可以根据需要增加新的请求处理类,满足开闭原则。
- 增强了给对象指派职责的灵活性。当工作流程发生变化,可以动态地改变链内的成员或者调动它们的次序,也可动态地新增或者删除责任。
- 责任链简化了对象之间的连接。每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句。
- 责任分担。每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
缺点:
- 不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
- 对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
- 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。
代码实现:
package mySelf;
public class ZhizeMoshi {
public static void main(String[] args) {
Handler hand1 = new ConnectHandler1();
Handler hand2 = new ConnectHandler2();
Handler hand3 = new ConnectHandler3();
// 设置下一个节点
hand1.setNext(hand2);
hand2.setNext(hand3);
hand3.setNext(null);
hand1.handlerRequest("dd");
}
}
// 抽象处理者角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
abstract class Handler {
private Handler handle;
public void setNext(Handler handle){
this.handle = handle;
}
public Handler getNext(){
return handle;
}
public abstract void handlerRequest(String msg);
}
// 具体处理者角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
class ConnectHandler1 extends Handler{
@Override
public void handlerRequest(String msg) {
if("00".equals(msg)){
System.out.println("1正在处理");
}else {
if(getNext() != null){
getNext().handlerRequest(msg);
}else {
System.out.println("无人处理");
}
}
}
}
class ConnectHandler2 extends Handler{
@Override
public void handlerRequest(String msg) {
if("aa".equals(msg)){
System.out.println("2正在处理");
}else {
if(getNext() != null){
getNext().handlerRequest(msg);
}else {
System.out.println("无人处理");
}
}
}
}
class ConnectHandler3 extends Handler{
@Override
public void handlerRequest(String msg) {
if("cc".equals(msg)){
System.out.println("3正在处理");
}else {
if(getNext() != null){
getNext().handlerRequest(msg);
}else {
System.out.println("无人处理");
}
}
}
}
二、策略模式
概念:定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。
优点:
- 多重条件语句不易维护,而使用策略模式可以避免使用多重条件语句,如 if...else 语句、switch...case 语句。
- 策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码。
- 策略模式可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的。
- 策略模式提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算法。
- 策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离。
缺点:
- 客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类。
- 策略模式造成很多的策略类,增加维护难度。
代码实现:
public class Celue{
public static void main(String[] args) {
Country country = new Country();
Speak chinese = new Chinese();
country.setCountry(chinese);
country.countrySay();
Janpanses janpanses = new Janpanses();
country.setCountry(janpanses);
country.countrySay();
}
}
// 环境类:持有一个策略类的引用,最终给客户端调用。
public class Country {
private Speak speak;
public Speak getCountry() {
return speak;
}
public void setCountry(Speak country) {
this.speak = country;
}
public void countrySay(){
speak.say();
}
}
// 具体策略类:实现了抽象策略定义的接口,提供具体的算法实现。
public class Chinese implements Speak{
@Override
public void say() {
System.out.println("我是中国人");
}
}
public class Janpanses implements Speak{
@Override
public void say() {
System.out.println("我是日本人");
}
}
//抽象策略类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
public interface Speak {
public void say();
}
三、享元模式
概念:运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似类的开销,从而提高系统资源的利用率。
优点:相同对象只要保存一份,这降低了系统中对象的数量,从而降低了系统中细粒度对象给内存带来的压力。相当于批量的单例模式。
缺点:
- 为了使对象可以共享,需要将一些不能共享的状态外部化,这将增加程序的复杂性。
- 读取享元模式的外部状态会使得运行时间稍微变长。
代码实现:
public class Xiangyuan {
public static void main(String[] args) {
XiangyuanFactory xiangyuanFactory = new XiangyuanFactory();
XiangyuanApi a = xiangyuanFactory.getFlyWeight("a");
XiangyuanApi a1 = xiangyuanFactory.getFlyWeight("a");
XiangyuanApi b = xiangyuanFactory.getFlyWeight("b");
XiangyuanApi b1 = xiangyuanFactory.getFlyWeight("b");
a.doSomething(new Unshare("xiangyuan"));
}
}
// 抽象享元角色:是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。
public interface XiangyuanApi {
public void doSomething(Unshare unshare);
}
// 享元工厂角色:负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。
public class XiangyuanFactory {
// 用于存储对象的容器
private static volatile HashMap<String, XiangyuanApi> map = new HashMap<>();
public synchronized XiangyuanApi getFlyWeight(String tag){
XiangyuanApi xiangyuanItem;
if(map.get(tag) != null){
System.out.println(tag+"已存在");
xiangyuanItem = map.get(tag);
}else {
System.out.println("创建对象"+tag);
xiangyuanItem = new XiangyuanItem(tag);
map.put(tag, xiangyuanItem);
}
return xiangyuanItem;
}
}
// 具体享元角色:实现抽象享元角色中所规定的接口。
public class XiangyuanItem implements XiangyuanApi{
private String tag;
public XiangyuanItem(String tag){
System.out.println(tag+"被创建");
this.tag = tag;
}
@Override
public void doSomething(Unshare unshare){
System.out.println("调用飞翔元对象"+tag);
System.out.println(unshare.getInfo());
}
}
// 非享元角色:是不可以共享的外部状态,它以参数的形式注入具体享元的相关方法中。
public class Unshare {
private String info;
Unshare(String info){
this.info = info;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
四、命令模式
概念:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存、传递、调用、增加与管理。
优点:
- 通过引入中间件(抽象接口)降低系统的耦合度。
- 扩展性良好,增加或删除命令非常方便。采用命令模式增加与删除命令不会影响其他类,且满足“开闭原则”。
缺点:
- 可能产生大量具体的命令类。因为每一个具体操作都需要设计一个具体命令类,这会增加系统的复杂性。
- 命令模式的结果其实就是接收方的执行结果,但是为了以命令的形式进行架构、解耦请求与实现,引入了额外类型结构(引入了请求方与抽象命令接口),增加了理解上的困难。不过这也是设计模式的通病,抽象必然会额外增加类的数量,代码抽离肯定比代码聚合更加难理解。
代码实现:
public class main {
public static void main(String[] args) {
Command command = new Command();
Invoker invoker = new Invoker(command);
invoker.exec();
}
}
// 抽象命令类角色:声明执行命令的接口,拥有执行命令的抽象方法 execute()。
public interface Mingling {
public void execute();
}
// 具体命令类角色:是抽象命令类的具体实现类,它拥有接收者对象,并通过调用接收者的功能来完成命令要执行的操作。
public class Command implements Mingling{
private Receiver receiver;
public Command(){
receiver = new Receiver();
}
@Override
public void execute() {
receiver.doProcess();
}
}
// 请求者角色:是请求的发送者,它通常拥有很多的命令对象,并通过访问命令对象来执行相关请求,它不直接访问接收者。
public class Invoker {
private Mingling mingling;
public Invoker(Mingling mingling){
this.mingling = mingling;
}
public void setMingling (Mingling mingling){
this.mingling = mingling;
}
public void exec(){
System.out.println("执行命令");
mingling.execute();
}
}
// 接收者角色:执行命令功能的相关操作,是具体命令对象业务的真正实现者。
public class Receiver {
public void doProcess(){
System.out.println("收到命令,开始执行任务");
}
}