面向可复用性和可维护性的设计模式
面向可复用性和可维护性的设计模式
设计模式
今天上课学习了几种设计模式,现就设计模式作出总结与思考。首先设计模式被分为三大类,并主要讲解了七种设计模式,本文给出一些具体的代码示例以作分析。
在对设计模式进行具体分析之前,先了解一下设计模式的概念----一种针对软件设计中给定上下文中常见问题的通用的可重用的解决方案,设计模式更强调多个类/对象之间的关系和交互过程。
-
创建型模式
工厂方法模式,创建对象时不指定确切的类。
-
结构型模式
适配器模式,允许具有不兼容接口的类一起工作,通过将自己的接口包装在已有类的接口上。
装饰器模式,动态添加/覆盖对象方法中的行为。
-
行为型模式
策略模式,允许在运行时选择一个算法。
模板模式,将算法的框架定义为一个抽象类,允许其子类提供具体的行为。
迭代器模式,按顺序访问对象的元素,而不暴露对象的底层表示形式。
访问者模式,通过将方法层次结构移动到一个对象来将算法从对象结构中分离出来。
创建型模式
工厂方法模式
工厂方法模式的核心思想是,对容易变化的地方,应该考虑用一个单独的类做创造的过程,这就是工厂。
我们采用工厂方法模式,定义一个用于创建对象的接口,但让子类来决定实例化哪个类,从而允许类将实例化推迟到子类。当client不知道/不确定要创建哪个具体类的实例,或者不想在client代码中指明要具体创建的实例时,用工厂方法。
优点:
- 消除将特定于应用程序的类绑定到代码的需要,在创建对象时不会对客户端暴露创建逻辑。
- 代码只处理产品接口,可以与任何用户定义的具体子类对象一起工作。
结构型模式
适配器模式
适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁,结合了两个独立接口的功能。通过增加一个接口,将已存在的子类封装起来,客户端面向接口编程,从而隐藏了具体子类。
举个例子,一个 LegacyRectangle类的display()方法期待收到参数“x, y, w, h” ,即左上角坐标+宽+高。但是客户端想要传递参数左上角坐标+右下角坐标。这种不一致可以通过添加一个额外的间接层来调和,比如一个适配器对象。
//初始模式,无法兼容委托
class LegacyRectangle {
void display(int x1, int y1, int w, int h) {... }
class Client {
public display() {
new LegacyRectangle().display(x1, y1, x2, y2);
}
}
//适配器模式
interface Shape {
void display(int x1, int y1, int x2, int y2);
}//Adaptor类实现抽象接口
class Rectangle implements Shape {
void display(int x1, int y1, int x2, int y2) {
new LegacyRectangle().display(x1, y1, x2-x1, y2-y1);
}
}//具体实现方法的适配
class LegacyRectangle{
void display(int x1, int y1, int w, int h) {...}
}//具体实现方法
class Client {
Shape shape = new Rectangle();
public display() {
shape.display(x1, y1, x2, y2);
}
}//对抽象接口编程,与LegacyRectangle隔离
装饰器模式
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。其结构如下所示:
-
Component接口:定义装饰物执行的公共操作
-
ConcreteComponent起始对象:在其基础上增加功能(装饰),将通用的方法放到此对象
-
Decorator抽象类:所有装饰类的基类,里面包含的成员变量 component 指向了被装饰的对象。
-
ConcreteDecorator:能够添加特性的装饰类,可以有任意多的ConcreteDecorator类,每个类都代表一个可以添加的特性。
以Stack为例展示其结构:
//接口
interface Stack {
void push(Item e);
Item pop();
}
//最基础的Stack功能
public class ArrayStack implements Stack {
... //rep
public ArrayStack() {...}
public void push(Item e) {...}
public Item pop() {...}
...
}
//The AbstractStackDecorator Class 一个用于decorator的基础类
public abstract class StackDecorator implements Stack {
protected final Stack stack;
public StackDecorator(Stack stack) {
this.stack = stack;
}
public void push(Item e) {
stack.push(e);
}
public Item pop() {
return stack.pop();
}
...
}
//The concrete decorator classes
public class UndoStack extends StackDecorator {
private final UndoLog log = new UndoLog();
public UndoStack(Stack stack) {
super(stack);
}
public void push(Item e) {
super.push(e);//基础功能通过基类中的delegation实现
log.append(UndoLog.PUSH, e);//新特性
}
public void undo() {
//implement decorator behaviors on stack 新特性
}
...
}
使用此装饰器模式的类
行为型模式
策略模式
在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。其实现结构如下:
举个例子,定义一个活动“doOperation”,其有加减乘。设计其策略模式如下:
public interface Strategy {
public int doOperation(int num1, int num2);
}
//不同的策略对象
public class OperationAdd implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
public class OperationSubtract implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
public class OperationMultiply implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 * num2;
}
}
//Context类
public class Context {
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2){
return strategy.doOperation(num1, num2);
}
}
public class StrategyPatternDemo {
public static void main(String[] args) {
Context context = new Context(new OperationAdd());
System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationSubtract());
System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
context = new Context(new OperationMultiply());
System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
}
}
优点:
1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。
模板模式
在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行
迭代器模式
这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示。也就是说客户端希望对放入容器 /集合类的一组ADT对象进行遍历访问,而无需关心容器的具体类型。其结构如下:
Iterator pattern:让自己的集合类实现Iterable接口,并实现自己的独特Iterator迭代器(hasNext, next, remove),允许客户端利用这个迭代器进行显式或隐式的迭代遍历。下面是两个实例,分别是接口和具体的类。
public interface Collection<E> extends Iterable<E> {
boolean add(E e);
boolean addAll(Collection<? extends E> c);
boolean remove(Object e);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);
boolean contains(Object e);
boolean containsAll(Collection<?> c);
void clear();
int size();
boolean isEmpty();
Iterator<E> iterator();
Object[] toArray()
<T> T[] toArray(T[] a);
…
}
public class Pair<E> implements Iterable<E> {
private final E first, second;
public Pair(E f, E s) { first = f; second = s; }
public Iterator<E> iterator() {
return new PairIterator();
}
private class PairIterator implements Iterator<E> {
private boolean seenFirst = false, seenSecond = false;
public boolean hasNext() { return !seenSecond; }
public E next() {
if (!seenFirst) { seenFirst = true; return first; }
if (!seenSecond) { seenSecond = true; return second; }
throw new NoSuchElementException();
}
public void remove() {
throw new UnsupportedOperationException();
}
}
}
访问者模式
在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。本质上是,将数据和作用于数据上的某种/些特定操作分离开来。其结构如下所示:
举个例子,一个电脑有键盘、鼠标、显示器等部件,使用访问者模式来设计如下所示:
//元素的接口
public interface ComputerPart {
public void accept(ComputerPartVisitor computerPartVisitor);
}
//扩展上述接口的实体类
public class Keyboard implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
public class Monitor implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
public class Mouse implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
public class Computer implements ComputerPart {
ComputerPart[] parts;
public Computer(){
parts = new ComputerPart[] {new Mouse(), new Keyboard(), new Monitor()};
}
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
for (int i = 0; i < parts.length; i++) {
parts[i].accept(computerPartVisitor);
}
computerPartVisitor.visit(this);
}
}
//一个访问者接口
public interface ComputerPartVisitor {
public void visit(Computer computer);
public void visit(Mouse mouse);
public void visit(Keyboard keyboard);
public void visit(Monitor monitor);
}
//此接口的实体访问者
public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
@Override
public void visit(Computer computer) {
System.out.println("Displaying Computer.");
}
@Override
public void visit(Mouse mouse) {
System.out.println("Displaying Mouse.");
}
@Override
public void visit(Keyboard keyboard) {
System.out.println("Displaying Keyboard.");
}
@Override
public void visit(Monitor monitor) {
System.out.println("Displaying Monitor.");
}
}
//使用 ComputerPartDisplayVisitor 来显示 Computer 的组成部分。
public class VisitorPatternDemo {
public static void main(String[] args) {
ComputerPart computer = new Computer();
computer.accept(new ComputerPartDisplayVisitor());
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构