【软件构造】面向可复用性和可维护性的设计模式

设计模式类别

  • 创建型模式:关注对象的创建
  • 结构型模式:类或对象的组成
  • 行为类模式:类或对象交流和分配责任的方式
Integer x = new Integer(2);
Integer y = new Integer(2);
System.out.println(x==y);//false
Integer x = 2;
Integer y = 2;
System.out.println(x==y);//true
//一来:Integer里弄了一个缓存,对于在 -128—127 之间的数值,会直接使用该缓存里的对象 ;
// 所以也就是说 在我们比较 integer = 20 的时候,其实拿取的是同一个对象,所以会返回true。
// 二来:因为321超出了 -128~127这个区间,那么系统会重新生成新的对象,所以比较的时候就会拿取不同的对象做比较,因此就会返回false。

创建型模式

工厂方法模式

工厂方法(虚拟构造器):当用户不知道要创建哪个具体类的实例,或者不想再用户代码中指明具体创建的示例时用工厂方法。

  • 常规情况下,直接创建具体对象,但是这样会导致子类公开
Product p = new ProductTwo();
  • 工厂模式下:
Product p = new ConcreteTwo().makeObject();
//创建一个新的类ConcreteTwo,用其中的方法makeobject创建新对象
  • 具体实现,Concrete product对要创建的类进行继承,然后创建的工厂方法(工厂方法既可以再ADT内部实现,也可以构造单独的工厂类)
//工厂方法定义
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
            return new SystemTrace;
    }
}

//用户调用工厂方法
Trace log1 = new Factory1.getTrace();
  • 可以实现静态工厂方法,再调用工厂方法时不需要创建具体工厂对象,直接通过类方法,代码如下
public class TraceFactory1 implements TraceFactory{
    //静态工厂方法只需要加修饰词statics
    public static Trace getTrace(){
        return new SystemTrace;
    }
}

//用户调用
Trace log1 = TraceFactory1.getTrace();//其实就差个new
  • 优势
    • 不需要构建具体基于平台的代码
    • 对于任意用户定义的ConcreteProduct均适用
  • 缺点
    • 使程序变得复杂

结构型模式

适配器模式

概念:通过增加一个接口将已存在的子类封装起来,用户面向接口编程,从而隐藏具体子类,目的是重用旧的结构到新的系统中,用户可以通过委托实现同一方法的不同实现

  • 通过委托实现:
//适配器接口
interface Shape{
    void display(int x1,int y1,int x2,int y2);
}

//适配器子类
class Rectangle implements Shape{
    void display(int x1,int y1,int x2,int y2){
        new LegacyRectangle().display(x1,y1,x2,y2);
    }
}

//适配器子类具体实现
class LegacyRectangle{
    void display(int x1,int y2,int x2,int y2){...}
}

//用户调用
class Client{
    Shape shape = new Rectangle();
    public display(){
        shape.display(){
            shape.diplay(){
                shape.display(x1,y1,x2,y2);
            }
        }
    }
}
装饰器模式
  • 场景需要:创建一个数据类型如 Stack ,如果需要用不同子类扩展不同的特性,并且需要实现特性的任意组合
    • 问题:不能用继承,因为会形成组合爆炸,并且存在大量代码重复(不符合程序美学 : )
  • 装饰器:对每一个特性构造一个子类,并且通过委派机制增加到对象上
    • Hint:装饰器既涉及继承又涉及委托
  • 具体实现示例:
    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(){
        ...
    }
}

//用于decorator的基础类
public abstract class StackDecorator implements Stack{
    protected final Stack stack;//通过委托实现Stack的基础功能
    public StackDecorator(Stack stack){//creator
        this.stack = stack;
    }
    public void push(Item e){
        stack.push(e);
    }
    public Item pop(){
        return stack.pop();
    }
    ...
}

//decorator 子类
public class UndoStack extends StackDecorator implements Stack{
    private final UndoLog log = new UndoLog();
    public UndoStack(Stack stack){ //creator
        super(stack);  //通过父类实现
    }
    public void push(Item e){
        log.append(UndoLog.PUSH,e);
        super.push(e);
    }
    public void undo(){
        //implement decorator behaviors on stack
    }
    ...
}

//用户使用
Stack s new ArrayStack();//实现一个基础类
Stack t new UndoStack(new ArrayStack());//实现一个Undo Stack
Stack t = new SecureStack(new SychronizedStack(new UndoStack(s)));//实现一个 secure synchronized undo stack,就是一层一层地装饰
  • 装饰器与继承
    • 装饰器在运行阶段构造特征(有错误在运行时报错),继承在编译阶段;
    • 装饰器包含多个合作对象,而继承只有一个、有具体类型地对象
    • 装饰器可以混合多个装饰

行为类模式

策略模式

  • 场景需要:有多种不同算法实现统一任务,但需要用户根据需要动态切换算法
  • 策略模式:为不同你地实现模式构造抽象接口,利用委托,运行时动态传入用户需要地算法实例
  • 优势:
    • 易于扩展新的算法
    • 将算法从用户上下文分离出来
      Stratey Pattern
//策略接口
public interface PaymentStrategy {
    public void pay(int amount);
}

//第一种策略
public class CreditCardStrategy implements PaymentStrategy {
    private String name;
    private String cardNumber;
    private String cvv;
    private String dateOfExpiry;
    public CreditCardStrategy(String nm, String ccNum, 
    String cvv, String expiryDate){
        this.name=nm;
        this.cardNumber=ccNum;
        this.cvv=cvv;
        this.dateOfExpiry=expiryDate;
    }
    @Override
    public void pay(int amount) {
        System.out.println(amount +" paid with credit card");
    }
}

//第二种策略
public class PaypalStrategy implements PaymentStrategy {
    private String emailId;
    private String password;
    public PaypalStrategy(String email, String pwd){
        this.emailId=email;
        this.password=pwd;
    }
    @Override
    public void pay(int amount) {
        System.out.println(amount + " paid using Paypal.");
    }
}

//调用策略
public class ShoppingCart {
    ...
    public void pay(PaymentStrategy paymentMethod){
        int amount = calculateTotal();
        paymentMethod.pay(amount);
    }
}

模板模式

  • 场景需要:做事情的步骤一样,但具体方法不同
  • 模板模式:共性的步骤在抽象类内公共实现,差异化的步骤在各个子类中实现,使用继承和重写实现模板模式,通常用于框架(黑盒?框架)实现
    模板模式UML图示例
//模板类(框架)
public abstract class OrderProcessTemplate {
    public boolean isGift;
    public abstract void doSelect();
    public abstract void doPayment();
    public final void giftWrap() {
        System.out.println("Gift wrap done.");
    }
    public abstract void doDelivery();
    public final void processOrder() {
        doSelect();
        doPayment();
        if (isGift)
            giftWrap();
        doDelivery();
    }
}

//具体实现
public class NetOrder extends OrderProcessTemplate {
    @Override
    public void doSelect() {}
    @Override
    public void doPayment() {}
    @Override
    public void doDelivery() {}
}

//用户调用
OrderProcessTemplate netOrder = new NetOrder();
netOrder.processOrder();

OrderProcessTemplate storeOrder = new StoreOrder();
storeOrder.processOrder();

迭代器

  • 问题场景:客户端希望遍历被放入容器/集合类的一组ADT对象,无需关心容器的具体类型,也就是说,不管对象被放进哪里,都应该提供同样的遍历方式
    迭代器UML示例图

visitor

  • 概念:为ADT预留一个可以扩展功能的接入点,外部实现代码可以在不改变ADT本身的情况下通过委托接入ADT
public interface ItemElement{
    public int accept(shoppingCarVisitor visitor);
}
public class Book implements ItemElement{
    private double price;
    ...
    public int accept(shoppingCarVisitor visitor){
        visitor.visit(this);
    }
}
public class Fruit implements ItemElement{
    private double price;
    ...
    public int accept(shoppingCarVisitor visitor){
        visitor.visit(this);
    }
}
public interface shoppingCarVisitor{
    public double visit(Book book);
    public double visit(Fruit fruit);
}
public class shoppingCarVisitorImp implements shoppingCarVisitor{
    public double visit(Book book){

    }
    public double visit(Fruit fruit){
        
    }
}
public class shoppingCarClient{
    ItemElement[] items = new ItemElement[]{
        new Book(20,"1234"),
        new Fruit(10,1,'Banana')
    }
    int total = calculate(items);
    public double calculate(items){
        shoppingCarVisitor visitor = new shoppingCarVisitorImp();
        double res = 0;
        for(ItemElement item:items){
            res+=item.accept(visitor);
        }
    }
}

设计模式的共性与差异

  • 共性样式1
    • 适配器
    • 模板模式
  • 共性样式2
    • 策略模式
    • 迭代器
    • 工厂模式
    • visitor
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值