设计模式类别:
- 创建型模式:关注对象的创建
- 结构型模式:类或对象的组成
- 行为类模式:类或对象交流和分配责任的方式
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
:装饰器既涉及继承又涉及委托
- 具体实现示例:
//接口定义
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,就是一层一层地装饰
- 装饰器与继承
- 装饰器在运行阶段构造特征(有错误在运行时报错),继承在编译阶段;
- 装饰器包含多个合作对象,而继承只有一个、有具体类型地对象
- 装饰器可以混合多个装饰
行为类模式
策略模式
- 场景需要:有多种不同算法实现统一任务,但需要用户根据需要动态切换算法
- 策略模式:为不同你地实现模式构造抽象接口,利用委托,运行时动态传入用户需要地算法实例
- 优势:
- 易于扩展新的算法
- 将算法从用户上下文分离出来
//策略接口
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);
}
}
模板模式
- 场景需要:做事情的步骤一样,但具体方法不同
- 模板模式:共性的步骤在抽象类内公共实现,差异化的步骤在各个子类中实现,使用继承和重写实现模板模式,通常用于
框架(黑盒?框架)实现
//模板类(框架)
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对象,无需关心容器的具体类型,也就是说,不管对象被放进哪里,都应该提供同样的遍历方式
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