几个设计模式

前言

这一段时间看商城的代码,觉得有必要对Java的设计模式进行一些复习,2018-10-24HeadFirst设计模式是HeadFirst中详细介绍的12种模式,这里对看到一些其他的几种模式进行补充。

构造者模式(Builder)

适用场景

当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,考虑使用构造者模式

类图

builder模式

通过AbstractBuilder来定义接口,而通过具体的实现来builder,调用相应的接口来生成对象。

builder模式与工厂模式挺像,都是为了生成对象,工程模式生成多种对象(1维、2维),builder模式仅生成一种。

举例

当一个构造函数的参数过多,而且有些还是可选项时,我们在实现上有2种方式:

  1. 通过定义多个构造函数来实现,每个构造函数的参数不同。

    public class Computer {
         ...
        public Computer(String cpu, String ram) {
            this(cpu, ram, 0);
        }
        public Computer(String cpu, String ram, int usbCount) {
            this(cpu, ram, usbCount, "罗技键盘");
        }
        public Computer(String cpu, String ram, int usbCount, String keyboard) {
            this(cpu, ram, usbCount, keyboard, "三星显示器");
        }
        public Computer(String cpu, String ram, int usbCount, String keyboard, String display) {
            this.cpu = cpu;
            this.ram = ram;
            this.usbCount = usbCount;
            this.keyboard = keyboard;
            this.display = display;
        }
    }
    
  2. 定义最小的构造函数,其他用setting来实现。

    public class Computer {
            ...
    
        public String getCpu() {
            return cpu;
        }
        public void setCpu(String cpu) {
            this.cpu = cpu;
        }
        public String getRam() {
            return ram;
        }
        public void setRam(String ram) {
            this.ram = ram;
        }
        public int getUsbCount() {
            return usbCount;
        }
    ...
    }
    

第一种的方式不太优雅,第二种不能保证在构造时候是适合的,通过setting使数据容易发生变化。

处理方案:Builder模式

builder模式是将这个类对象的构建,交给专门的builder类来实现。通过调用builder的函数,来准备数据,最后调用build,来生成对象。

public class Computer {
    private final String cpu;//必须
    private final String ram;//必须
    private final int usbCount;//可选
    private final String keyboard;//可选
    private final String display;//可选

    private Computer(Builder builder){
        this.cpu=builder.cpu;
        this.ram=builder.ram;
        this.usbCount=builder.usbCount;
        this.keyboard=builder.keyboard;
        this.display=builder.display;
    }
    public static class Builder{
        private String cpu;//必须
        private String ram;//必须
        private int usbCount;//可选
        private String keyboard;//可选
        private String display;//可选

        public Builder(String cup,String ram){
            this.cpu=cup;
            this.ram=ram;
        }

        public Builder setUsbCount(int usbCount) {
            this.usbCount = usbCount;
            return this;
        }
        public Builder setKeyboard(String keyboard) {
            this.keyboard = keyboard;
            return this;
        }
        public Builder setDisplay(String display) {
            this.display = display;
            return this;
        }        
        public Computer build(){
            return new Computer(this);
        }
    }
  //省略getter方法
}

使用时:

Computer computer=new Computer.Builder("因特尔","三星")
                .setDisplay("三星24寸")
                .setKeyboard("罗技")
                .setUsbCount(2)
                .build();

这里是将Builder作为了Computer的内部类,其实并不是必须的。

提供者模式(Provider)

Provider模式是工厂模式与策略模式的结合,即工厂生成对象,而如何生成对象则由策略来决定,这个策略就是provider。

public interface ILoggerProvider : IDisposable
{
    ILogger CreateLogger(string categoryName);
}

public interface ILoggerFactory : IDisposable
{
    ILogger CreateLogger(string categoryName);
    void AddProvider(ILoggerProvider provider);
}

可以往工厂里面添加 Provider。也就是说工厂里面可能存在着许许多多的提供程序。而这些提供程序可能都将是最后工厂创建出结果的必要支撑。

桥接模式(Bridge)

参考

适用场景

如果一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立进行扩展。可以通过将变化维度抽象出各自的类,通过组合方式再结合起来,这样防止因为很多继承带来的问题。

类图

classDiagram Abstraction <|-- RefinedAbstraction Abstraction *-- Implementor:组合 Implementor <|-- ConcreteImplementorA Implementor <|-- ConcreteImplementorB Abstraction : -impl:Implementor Abstraction : +Abstraction() Abstraction : +operation():void class RefinedAbstraction{ +RefinedAbstraction() +otherOperation():void } class Implementor{ +operationImpl() } class ConcreteImplementorA{ +operationImpl() } class ConcreteImplementorB{ +operationImpl() }

桥梁模式所涉及的角色有:

  • 抽象化(Abstraction)角色:抽象化给出的定义,并保存一个对实现化对象的引用。
  • 修正抽象化(RefinedAbstraction)角色:扩展抽象化角色,改变和修正父类对抽象化的定义。
  • 实现化(Implementor)角色:这个角色给出实现化角色的接口,但不给出具体的实现。必须指出的是,这个接口不一定和抽象化角色的接口定义相同,实际上,这两个接口可以非常不一样。实现化角色应当只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的操作。
  • 具体实现化(ConcreteImplementor)角色:这个角色给出实现化角色接口的具体实现。

举例

如咖啡,在容量维度上大杯、中杯、小杯...,在添加物维度上有牛奶、糖、蜂蜜...

如果用继承来完成,以上就有3×3种咖啡。这样将容量维度变成自身(Abstraction),然后将添加物抽象成实现(Implementor),然后让Abstraction来组合Implementor。

//Abstraction
public abstract class Coffee {
    protected ICoffeeAdditives additives;
    public Coffee(ICoffeeAdditives additives){
        this.additives=additives;
    }
    public abstract void orderCoffee(int count);
}

//RefinedAbstraction:为Abstraction增加新的功能,应对变化
public abstract class RefinedCoffee extends Coffee {
    public RefinedCoffee(ICoffeeAdditives additives) {
        super(additives);
    }
    public void checkQuality(){
        Random ran=new Random();
        System.out.println(String.format("%s 添加%s",additives.getClass().getSimpleName(),ran.nextBoolean()?"太多":"正常"));
    }
}

实现层的抽象

public interface ICoffeeAdditives {
    void addSomething();
}
//加奶
public class Milk implements ICoffeeAdditives {
    @Override
    public void addSomething() {
        System.out.println("加奶");
    }
}
//加糖
public class Sugar implements ICoffeeAdditives {
    @Override
    public void addSomething() {
        System.out.println("加糖");
    }
}

使用:

public static void main(String[] args) {
        //点两杯加奶的大杯咖啡
        RefinedCoffee largeWithMilk=new LargeCoffee(new Milk());
        largeWithMilk.orderCoffee(2);
        largeWithMilk.checkQuality();
}

访问者模式(Visitor)

适用场景

为对象的集合增加新的功能,而不影响对象及集合本身时,使用vistor模式。

类图

访问者模式

涉及角色

  • element,对象
  • ObjectStructure,对象集合
  • Visitor:访问者,也就是添加新功能的地方。

举例

我们都知道财务都是有账本的,这个账本就可以作为一个对象集合,而它其中的元素有两种,收入和支出;

而查看账本的人可能有这样几种,比如老板,会计事务所的注会,财务主管,等等。而这些人在看账本的时候显然目的和行为是不同的。

元素:

public interface Bill {
   void accept(AccountBookViewer v);
}
public class ConsumeBill implements Bill {
	private double amount;
    private String item;

    public ConsumeBill(double amount, String item) {
        super();
        this.amount = amount;
        this.item = item;
    }

	@Override
	public void accept(AccountBookViewer v) {
      v.view(this);
	}
}

public class IncomeBill implements Bill {
	private double amount;
    private String item;
    
    public IncomeBill(double amount, String item) {
        super();
        this.amount = amount;
        this.item = item;
    }
    
	@Override
	public void accept(AccountBookViewer v) {
      v.view(this);
	}
}

访问者类:

public abstract class AccountBookViewer {
	//查看消费的单子
  abstract  void view(ConsumeBill bill);
    //查看收入的单子
  abstract void view(IncomeBill bill);
}

// 老板
public class Boss extends AccountBookViewer {
	private double totalIncome;
    private double totalConsume;
	
	@Override
	void view(ConsumeBill bill) {
		totalConsume += bill.getAmount();
	}
	@Override
	void view(IncomeBill bill) {
		totalIncome += bill.getAmount();
	}
	
	public double getTotalIncome() {
        System.out.println("老板查看一共收入多少,数目是:" + totalIncome);
        return totalIncome;
    }
    public double getTotalConsume() {
        System.out.println("老板查看一共花费多少,数目是:" + totalConsume);
        return totalConsume;
    }
}

// 会计
public class Cpa extends AccountBookViewer {
	//注会在看账本时,如果是支出,则如果支出是工资,则需要看应该交的税交了没
    public void view(ConsumeBill bill) {
        if (bill.getItem().equals("工资")) {
            System.out.println("注会查看工资是否交个人所得税。");
        }
    }
    //如果是收入,则所有的收入都要交税
    public void view(IncomeBill bill) {
        System.out.println("注会查看收入交税了没。");
    }
}

最后是对象集合:

public class AccountBook {
	//单子列表
    private List<Bill> billList = new ArrayList<Bill>();
    //添加单子
    public void addBill(Bill bill){
        billList.add(bill);
    }
    //供账本的查看者查看账本
    public void show(AccountBookViewer viewer){
        for (Bill bill : billList) {
            bill.accept(viewer);
        }
    }
}

责任链

适用场景

有多个handler要对一个request进行处理

当有一个以上的对象有机会能够处理某个请求的时候,使用责任链模式。

类图

责任链

举例

handler

// 定义hanlder接口
public interface Filter {
    void doFilter(String data);
}

class FilterEgg implements Filter {
    @Override
    public void doFilter(String data) {
        //doSomething
    }
}

class FilterAoBing implements Filter {
    @Override
    public void doFilter(String data) {
        //doSomething
    }
}
...

责任链

public class FilterChain {
    List<Filter> filters = new ArrayList<>();

    public FilterChain() {
        filters.add(new FilterEgg());
        filters.add(new FilterAoBing());
        ...
    }
    public void processData(String data) {
        for (Filter filter : filters) {
            filter.doFilter(data);
        }
    }
}

client

public class Client {
    public void handlerRequest(Request request) {
        // 得到请求的数据
        String data = request.getData();
        FilterChain filterChain = new FilterChain();
        // 处理数据
        filterChain.processData(data);
    }
}

引申

这里的责任链是通过for循环遍历各个hander,然后调用处理函数,在Java Web中,有Filter,它的处理就不是通过for循环遍历。

它通过FilterChain与Filter相互调用,逐渐递进的方式来完成各个handler的处理。这种方式的好处是在filter既可以在controller之前处理数据,可以在contrller之后处理数据。

# 语言 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×