软件构造 - 设计模式总结之可维护性

一.Creational patterns 创造型模式

Factory 工厂模式*

概念

当client不知道要创建哪个具体类的实例,或者不想在client代码中指明要具体创建的实例时,用工厂方法。
定义一个用于创建对象的接口,让其子类来决定实例化哪一个类,从而使一个类的实例化延迟到其子类。

使用场景

  • jdbc连接数据库
  • 硬件访问
  • 降低对象的产生和销毁

区别:

通常情况下进行对象创建:(client直接创建具体对象)

Product p = new ProductTwo();

工厂模式下:

Product p = new ConcreteTwo().makeObject();

代码示例

//工厂实现的接口
interface TraceFactory {
	public Trace getTrace();
	public Trace getTrace(String type);
	void otherOperation(){};//还可实现其他功能
}
//工厂方法的实现
public class Factory1 implements TraceFactory {
	//有新的具体类时 可以在工厂类里修改或增加新的工厂函数 不影响客户端代码
	public Trace getTrace() {
		return new SystemTrace();
	}
}
public class Factory2 implements TraceFactory {
	public Trace getTrace(String type) {//根据输入类型决定创建哪个具体产品
		if(type.equals(“file”)
			return new FileTrace();
		else if (type.equals(“system”)
			return new SystemTrace();
	}
}

也可采用静态工厂方法实现,在获取想要得到的产品时不需将工厂类实例化,直接调用工厂方法即可
遵循OCP原则:对扩展的开放,对修改已有代码的封闭

Abstract Factory 抽象工厂模式

概念

提供接口以 创建一组相关/相互依赖的对象 ,但不需要指明其具体类。
解决类似固定搭配的问题
在这里插入图片描述
注释:
创建的不是一个完整产品,而是“产品族”(遵循固定搭配规则的多类产品的实例),得到的结果是:多个不同产品的object,各产品创建过程对client可见,但“搭配”不能改变。

本质上,Abstract Factory是把多类产品的factory method组合在一起
如果不使用抽象工厂,直接采用各类的工厂可能会导致搭配错误

抽象工厂模式与工厂模式的区别

抽象工厂模式工厂模式
创建多个类型的对象创建一个对象
多个factory方法一个factory方法
使用组合/委派使用继承/子类型

Builder 构造器模式

概念

创建复杂对象,包含多个组成部分。将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

与抽象工厂模式的区别:

client要的不是一堆零散的objects (abstract factory那样的结果),而是一个完整的产品,client不关心其中的细节组成部分是什么、如何创建

  • 抽象工厂模式:创建的不是一个完整产品,而是“产品族”(遵循固定搭配规则的多类产品实例),得到的结果是:多个不同产品的实例object,各产品创建过程对client可见,但“搭配”不能改变。
  • 构造器模式:创建的是一个完整的产品,有多个部分组成,client不需了解每个部分是怎么创建、各个部分怎么组合,最终得到一个产品的完整object

Product 产品类: 通常是实现了模板方法模式,也就是有模板方法和基本方法。

Builder 抽象建造者: 规范产品的组建,一般是由子类实现。

ConcreteBuilder 具体建造者: 实现抽象类定义的所有方法,并且返回一个组建好的对象。

Director 导演类: 负责安排已有模块的顺序,然后告诉 Builder 开始建造
在这里插入图片描述

使用场景

  • 相同的方法,不同的执行顺序,产生不同的事件结果时,可以采用建造者模式。

  • 多个部件或零件,都可以装配到一个对象中,但是产生的运行结果又不相同时,则可以使用该模式。

  • 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能,这个时候使用建造者模式非常合适。

代码示例

/* "Product" */
class Pizza {
	private String dough = "";
	private String sauce = "";
	private String topping = "";
	public void setDough(String dough) {
		this.dough = dough;
	}
	public void setSauce(String sauce) {
		this.sauce = sauce;
	}
	public void setTopping(String topping) {
		this.topping = topping;
	}
}
/* "Abstract Builder" */
abstract class PizzaBuilder {
	protected Pizza pizza;
	public Pizza getPizza() {
		return pizza;
	}
	public void createNewPizzaProduct() {
		pizza = new Pizza();
	}
	public abstract void buildDough();
	public abstract void buildSauce();
	public abstract void buildTopping();
}
/* "ConcreteBuilder 1" */
//具体的builder子类中,override三个抽象方法,分别构建三个parts
class SpicyPizzaBuilder extends PizzaBuilder {
	public void buildDough() {
		pizza.setDough("pan baked");
	}
	public void buildSauce() {
		pizza.setSauce("hot");
	}
	public void buildTopping() {
		pizza.setTopping("pepperoni+salami");
	}
}
/* "ConcreteBuilder 2" */
class HawaiianPizzaBuilder extends PizzaBuilder {
	public void buildDough() {
		pizza.setDough("cross");
	}
	public void buildSauce() {
		pizza.setSauce("mild");
	}
	public void buildTopping() {
		pizza.setTopping("ham+pineapple");
	}
}
/* "Director" */
class Waiter {
	private PizzaBuilder pizzaBuilder;
	public void setPizzaBuilder(PizzaBuilder pb) {
		pizzaBuilder = pb;
	}
	public Pizza getPizza() {
		return pizzaBuilder.getPizza();
	}
	public void constructPizza() {
		pizzaBuilder.createNewPizzaProduct();
		pizzaBuilder.buildDough();
		pizzaBuilder.buildSauce();
		pizzaBuilder.buildTopping();
	}
}
/* A customer ordering a pizza. */
public class PizzaBuilderDemo {
	public static void main(String[] args) {
		Waiter waiter = new Waiter();
		PizzaBuilder hawaiianPizzabuilder = new HawaiianPizzaBuilder();//Client使用不同的builder子类创建不同的产品
		PizzaBuilder spicyPizzaBuilder = new SpicyPizzaBuilder();
		waiter.setPizzaBuilder( hawaiianPizzabuilder );//建立waiter和builder之间的delegation关系
		waiter.constructPizza();
		Pizza pizza = waiter.getPizza();
	}
}

二. Structural patterns 结构型模式

Bridge 桥连模式

概念

通过delegation+inheritance建立两个具体类之间的关系;将抽象和实现解耦, 使得两者可以独立地变化。

Abstraction——抽象化角色: 它的主要职责是定义出该角色的行为,同时保存一个对实现化角色的引用,该角色一般是抽象类。

Implementor——实现化角色: 它是接口或者抽象类,定义角色必需的行为和属性。

RefinedAbstraction——修正抽象化角色: 它引用实现化角色对抽象化角色进行修正。

ConcreteImplementor——具体实现化角色: 它实现接口或抽象类定义的方法和属性。
在这里插入图片描述

与策略模式的区别

  • Bridge: structural pattern 强调双方的run time delegation linking
    一个类A的对象中有其他类B的对象作为其组成部分,但A的对象具体绑定到B的哪个具体子类的实现?在运行时通过delegation加以组合,并永久保存这种delegation关系。

  • Strategy: behavioral pattern 强调一方run-time使用另一方的“算法”
    “算法”通常实现为“类的某个方法”的形式,strategy的目的并非在“调用算法的类”与“被调用算法所在的类”之间建立起永久联系,而只是帮助前者临时使用后者中的“算法”,前者无需永久保存后者的实例。

使用场景

  • 不希望或不适用使用继承的场景
  • 接口或抽象类不稳定的场景
  • 重用性要求较高的场景

代码示例

public class Circle extends Shape {
	private int x, y, radius;
	public Circle(int x, int y, int radius, DrawAPI drawAPI) {
		super(drawAPI);
		this.x = x; 
		this.y = y; 
		this.radius = radius;
	}
	public void draw() {
		drawAPI.drawCircle(radius,x,y);//将draw这个责任delegate到drawAPI这个接口的具体实例去执行
	}
}

Proxy 代理模式

概念

为其他对象提供一种代理以控制对这个对象的访问

与Adaptor模式的区别:

Adapter: structural pattern,目的:消除不兼容,目的是B以客户端期望的统一的方式与A建立起联系

Proxy: behavioral pattern 目的:隔离对复杂对象的访问,降低难度/代价,定位在“访问/使用行为”

分类

  • 普通代理: 在该模式下,调用者只知代理而不用知道真实的角色是谁,屏蔽了真实角色的变更对高层模块的影响,真实的主题角色想怎么修改就怎么修改,对高层次的模块没有任何的影响,只要你实现了接口所对应的方法,该模式非常适合对扩展性要求较高的场合。

  • 强制代理: 强制代理的概念就是要从真实角色查找到代理角色,不允许直接访问真实角色。高层模块只要调用 getProxy 就可以访问真实角色的所有方法,它根本就不需要产生一个代理出来,代理的管理已经由真实角色自己完成。

区别:普通代理就是我们要知道代理的存在,也就是类似的 GamePlayerProxy 这个类的存在,然后才能访问;强制代理则是调用者直接调用真实角色,而不用关心代理是否存在,其代理的产生是由真实角色决定的。

  • 动态代理: 根据被代理的接口生成所有的方法,也就是说给定一个接口,动态代理会宣称“我
    已经实现该接口下的所有方法了”。两条独立发展的线路。动态代理实现代理的职责,业务逻辑 Subject 实现相关的逻辑功能,两者之间没有必然的相互耦合的关系。通知 Advice 从另一个切面切入,最终在高层模块也就是 Client 进行耦合,完成逻辑的封装任务。

意图:横切面编程,在不改变我们已有代码结构的情况下增强或控制对象的行为。
首要条件:被代理的类必须要实现一个接口。

代码示例

public class RealImage implements Image {
	private String fileName;
	public RealImage(String fileName){
		this.fileName = fileName;
		loadFromDisk(fileName);
	}
	@Override
	public void display() {}
	private void loadFromDisk(String fileName){}//不使用代理模式 每次加载的代价很高
}
public class ProxyImage implements Image {
	private Image realImage;
	private String fileName;
	public ProxyImage(String fileName){
		this.fileName = fileName;
	}
	@Override
	public void display() {
		if(realImage == null){ //当display时发现对象没有被加载在进行delegation
			realImage = new RealImage(fileName);
		}
		realImage.display();
	}
}

Composite 组合模式

概念

将对象组合成树形结构以表示 “部分-整体” 的层次结构,使得用户对单个对象和组合对象的使用具有一致性。

与Decorator区别:

Composite: structural pattern 目的是在同类型的对象之间建立起树型层次结构,一个上层对象可包含多个下层对象
Decorator: structural pattern 强调的是同类型对象之间的“特性增加”问题,它们之间是平等的,区别在于 “拥有特性”的多少,每次decoration只能作用于一个object。

使用场景

  • 维护和展示部分-整体关系的场景,如树形菜单、文件和文件夹管理。

  • 从一个整体中能够独立出部分模块或功能的场景。

  • 只要是树形结构,就考虑使用组合模式。

代码示例

public class Composite extends Component {
    //构件容器
    private ArrayList<Component> componentArrayList = new
            ArrayList<Component>();
    //增加一个叶子构件或树枝构件
    public void add(Component component){
        this.componentArrayList.add(component);
    }
    //删除一个叶子构件或树枝构件
    public void remove(Component component){
        this.componentArrayList.remove(component);
    }
    //获得分支下的所有叶子构件和树枝构件
    public ArrayList<Component> getChildren(){
        return this.componentArrayList;
    } 
}

三.Behavioral patterns

Observer 观察者模式***

概念

定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。

Subject 被观察者: 定义被观察者必须实现的职责,它必须能够动态地增加、取消观察者。它一般是抽象类或者是实现类,仅仅完成作为被观察者必须实现的职责:管理观察者并通知观察者。

Observer 观察者: 观察者接收到消息后,即进行 update(更新方法)操作,对接收到的信息进行处理。

ConcreteSubject 具体的被观察者: 定义被观察者自己的业务逻辑,同时定义对哪些事件进行通知。

ConcreteObserver 具体的观察者: 每个观察在接收到消息后的处理反应是不同,各个观察者有自己的处理逻辑。
在这里插入图片描述

使用场景

  • 关联行为场景。需要注意的是,关联行为是可拆分的,而不是“组合”关系。
  • 事件多级触发场景。
  • 跨系统的消息交换场景,如消息队列的处理机制

代码示例

public class Subject {
	private List<Observer> observers = new ArrayList<Observer>();//维持一组“对自己感兴趣的”对象
	private int state;
	public int getState() {return state;}
	public void setState(int state) {
		this.state = state;
		notifyAllObservers();//在自己状态变化时,通知所有“粉丝”
	}
	//允许“粉丝”调用该方法向自己注册,将其加入队列
	public void attach(Observer observer){observers.add(observer);}
	private void notifyAllObservers(){
		for (Observer observer : observers) {
			observer.update();
		}
	} 
}
//粉丝的抽象接口
public abstract class Observer {
	protected Subject subject;
	public abstract void update();
}
public class BinaryObserver extends Observer{
	//构造时,指定自己的“偶像”subject,把自己注册给它
	public BinaryObserver(Subject subject){
		this.subject = subject;
		this.subject.attach(this);
	}
	@Override
	public void update() {
		System.out.println( "Binary String: " + Integer.toBinaryString( subject.getState() ) ); 
	}
}

Vistor 访问者模式

概念

本质上:将数据和作用于数据上的某种/些特定操作分离开来(封装一些作用于某种数据结构中的各元素的操作, 它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。)

为ADT预留一个将来可扩展功能的“接入点”,外部实现的功能代码可以在不改变ADT本身的情况下通过delegation接入ADT

Visitor——抽象访问者: 抽象类或者接口,声明访问者可以访问哪些元素,具体到程序中就是 visit 方法的参数定义哪些对象是可以被访问的。

ConcreteVisitor——具体访问者: 它影响访问者访问到一个类后该怎么干,要做什么事情。

Element——抽象元素: 接口或者抽象类,声明接受哪一类访问者访问,程序上是通过 accept 方法中的参数来定义的。

ConcreteElement——具体元素: 实现 accept 方法,通常是 visitor.visit(this),基本上都形成了一种模式了。

ObjectStruture——结构对象: 元素产生者,一般容纳在多个不同类、不同接口的容器,如 List、Set、Map 等,在项目中,一般很少抽象出这个角色。
在这里插入图片描述

和迭代器的区别:

  • Iterator: behavioral pattern 迭代器:以遍历的方式访问集合数据而无需暴露其内部表示,将“遍历”这项功能delegate到外部的iterator对象。
  • Visitor: behavioral pattern 在特定ADT上执行某种特定操作,但该操作不在ADT内部实现,而是delegate到独立的visitor对象,客户端可灵活扩展/改变visitor的操作算法,而不影响ADT

和策略模式的联系与区别

二者都是通过delegation建立两个对象的动态联系

  • Visitor强调是的外部定义某种对ADT的操作,该操作于ADT自身关系不大(只是访问ADT),故ADT内部只需要开放accept(visitor)即可,client通过它设定visitor操作并在外部调用。
  • Strategy则强调是对ADT内部某些要实现的功能的相应算法的灵活替换。这些算法是ADT功能的重要组成部分,只不过是delegate到外部strategy类而已。

区别:

  • visitor是站在外部client的角度,灵活增加对ADT的各种不同操作(哪怕ADT没实现该操作)
  • strategy则是站在内部ADT的角度,灵活变化对其内部功能的不同配置。

使用场景

  • 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作,也就说是用迭代器模式已经不能胜任的情景。

  • 需要对一个对象结构中的对象进行很多不同并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。

代码示例

public class CompensationVisitor implements Visitor {
	// 将其中的数据和一些操作分离开
    @Override
    public void Visit(Element element) {
        // TODO Auto-generated method stub
        Employee employee = ((Employee) element);

        System.out.println(
                employee.getName() + "'s Compensation is " + (employee.getDegree() * employee.getVacationDays() * 10));
    }

}

Mediator 中介者模式

概念

用一个中介对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散, 而且可以独立地改变它们之间的交互。

使用场景

中介者模式适用于多个对象之间紧密耦合的情况,紧密耦合的标准是:在类图中出现了蜘蛛网状结构,即每个类都与其他的类有直接的联系。

Command 命令模式

概念

将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。

使用场景

认为是命令的地方就可以采用命令模式,例如,在 GUI 开发中,一个按钮的点击是一个命令,可以采用命令模式;模拟 DOS 命令的时候,当然也要采用命令模式;触发-反馈机制的处理等。

Chain of responsibility 责任链模式

概念

使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。

职责

抽象的处理者实现三个职责:

1、定义一个请求的处理方法 handleMessage,唯一对外开放的方法;

2、定义一个链的编排方法 setNext,设置下一个处理者;

3、定义了具体的请求者必须实现的两个方法:定义自己能够处理的级别getHandlerLevel 和具体的处理任务 echo。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值