设计模式理解(一)

一、简单工厂模式

在实例化对象时,通常使用new,但是这样耦合度就比较高。工厂模式就是将构造对象的过程抽象为一个类,实现解耦。简单工厂是面向过程到面向对象的抽象,使用者不关心创建过程。

二、工厂方法模式

简单工厂的升级版,创建对象的方法抽象为抽象方法,子类决定要实例化的类型。将对象的实例化推迟到子类。

三、抽象工厂模式

抽象工厂是工厂方法的升级,抽象工厂模式中可以定义实现多个接口,一个工厂可以生成多个产品类。

如一个工厂可以使用同种原料产出轿车、suv,一个工厂可以产出各种品牌的沙发和座椅;

例:一个工厂生产不同品牌电脑的配件

// 创造配件的抽象
public abstract class AbstractFactory{
// RAM
    public abstract void createRAM(); 
// CPU
    public abstract void createCPU();
// Mouse
    public abstract void createMouse();
}

// 配件的配置抽象
public abstract class RAM{
    public abstract void showRAM();
}
public abstract class CPU{
    public abstract void showCPU();
}
public abstract class Mouse{
    public abstract void showMouse();
}

// 具体工厂--华为实现
public class HWFactory extends AbstractFactory{
    @Override
    public void createRAM(){
        new HWRAM().showRAM();
    } 
     @Override
    public void createCPU(){
        new HWCPU().showCPU();
    }
     @Override
    public void createMouse(){
        new HWMouse().showMouse();
    }
}
// 具体工厂--小米实现
public class XMFactory extends AbstractFactory{
    @Override
    public void createRAM(){
        new XMRAM().showRAM();
    } 
     @Override
    public void createCPU(){
        new XMCPU().showCPU();
    }
     @Override
    public void createMouse(){
        new XMMouse().showMouse();
    }
}

// 具体品牌的配件配置实现
public class HWRAM extends RAM{
    @Override
    public void showRAM(){
        System.out.println("HW RAM");
    }
}
public class HWCPU extends CPU{
    @Override
    public void showCPU(){
        System.out.println("HW CPU");
    }
}
public class HWMouse extends Mouse{
    @Override
    public void showMouse(){
        System.out.println("HW Mouse");
    }
}

四、建造者模式:将产品和建造过程解耦

很多产品的建造流程一样,可以抽象

Product(产品角色):一个具体的产品对象

Builder(抽象建造者):创建一个Product对象的各个部件指定的接口/抽象类

ConcreteBuilder(具体建造者):实现接口,构建和装配各个部件

Director(指挥者):构建一个使用Builder接口的对象。主要作用:一是隔离客户与对象的生产过程,二是:负责控制产品对象的生产过程。

指挥者向外对接诉求,接收业务,给出产品

例:经理说要请大家吃奶茶(product),于是选择一家奶茶店茶百道(Builder),你就去店里找到店长(Director)说了清单,店长让你稍等十分钟;接着店长找到两位店员(ConcreteBuilder)安排下去各种口味及注意事项与时间要求,不一会儿在店长的指挥下奶茶好了,你接到通知今天不喝奶茶了哦(完蛋)。

// 指挥者向外对接诉求,接收业务,给出产品
public abstract class TeaBuilder{
    protected Tea tea = new Tea();
    public abstract void buildIce();
    public abstract void buildMilk();
    public Tea build(){
        return tea;
    }
}

public class Director {
    TeaBuilder teaBuilder;
    
    public Director(TeaBuilder teaBuilder){
        this.teaBuilder = teaBuilder;
    }

    public Tea constructTea(){
        // 先加冰
        teaBuilder.buildIce();
        // 再加牛奶
        teaBuilder.buildMilk();
        return teaBuilder.build();
    }
}

public class ChaBaiDaoTea extends TeaBuilder{
    @Override
    public void buildIce(){
        tea.setTemperature(5);
    }
    @Override
    public void buildMilk(){
        tea.setTaste("milk");
    }
}

public static void main(String[] args){
    TeaBuilder chaBaiDaoBuilder = new ChaBaiDaoTea();
    Director director = new Director(chaBaiDaoBuilder);
    Tea tea = director.constructTea();
}

五、桥接模式:提高系统的可扩充性

角色如下:

抽象化(Abstraction)角色:定义抽象类,并包含一个对实现化对象的引用。

拓展抽象化(Refined Abstraction)角色:是抽象化角色的子类,实现父类中的业务方法,并通过聚合关系调用实现角色中的业务方法。

实现化(Implementor)角色:定义实现化角色,供拓展抽象化角色调用。

具体实现化(Concrete Implementor)角色:给出实现化角色接口的具体实现。

当一个类存在两个独立变化维度,且都需要扩展时,桥接模式可以使它们在抽象层建立一个关系(对象和对象行为独立变化,组合一起配合使用)。通常,将类的一些普通业务方法和与之关系最密切的维度设计为“抽象类”(抽象部分),将另一个维度设计为“实现类”层次(实现部分)。

例:开发一个跨平台的视频播放器,可在不同操作平台上播放多种格式视频文件。(两个维度:平台、格式)

// 用心体会实现和继承,抽象的初心
// 视频文件,实现化角色
public interface VideoFile{
    // 解码功能
    void decode(String fileName);
}

// avi文件,具体实现化角色
public class AVIFile implements VideoFile{
    @Override
    public void decode(String fileName){
        System.out.println("avi文件:"+fileName)
    }
}
// rmvb文件,具体实现化角色
public class RMVBFile implements VideoFile{
    @Override
    public void decode(String fileName){
        System.out.println("avi文件:"+fileName)
    }
}

// 操作系统版本,拓展抽象化角色
public abstract class OperatingSysVersion{
    // 聚合实现化对象
    protected VideoFile videoFile;

    public OperatingSysVersion(VideoFile videoFile){
        this.videoFile = videoFile;
    }
    // 播放文件的方法
    public abstract void play(String fileName);
}

// windows版本
public class Windows extends OperatingSystem{
    public Windows(VideoFile videoFile){
        super(videoFile);
    }

    public void play(String fileName){
        videoFile.decode(fileName);
    }
}
// mac版本
public class Mac extends OperatingSystem{
    public Mac(VideoFile videoFile){
        super(videoFile);
    }

    public void play(String fileName){
        videoFile.decode(fileName);
    }
}

// 测试类
public static void main(String[] args){
    OperatingSystem os = new Mac(new AVIFile());
    os.play("功夫");
}

六、组合模式

Component:组合中对象声明接口,用于访问和管理Component子部件。Component可以是抽象类或者接口。

Leaf:组合中叶子节点,没有子节点。

Composite:非叶子节点,用于存储子部件,在Component接口实现子部件的相关操作,如操作删除行为。

// 文件夹的经典案例
// 抽象代码如下
// 抽象构件
public abstract class Component{
    //增加
    public void add(Component c){
        throw new UnsuportedOperationException();
    }
    // 删除
    public void remove(Componnet c){
        throw new UnsupportedOperationException();
    }
    //获取成员
    public Component getChild(int i){
        throw new UnsupportedOperationException();
    }
    //业务方法
    public void operaion(){
        throw new UnsupportedOperationException();
    }
}
//叶子构件--只需实现业务方法,其他的默认继承
public class Leaf extends Component{
    @Override
    public void operation(){
        System.out.println("叶子节点")
    }
}
//容器构件
public class Composite extends Component{
    private List<Component> list = new ArrayList<Component>();
    
    @Override
    public void add(Component c){
        list.add(c);
    }
    @Override
    public void remove(Component c){
        list.remove(c);
    }
    @Override
    public Component getChild(int i){
        return list.get(i); 
    }
    @Override
    public void operation(){
        for(Component child: list){
            child.operation();
        }
    }
}

容器构件中实现了抽象构件中声明的所有方法,因为组合模式中,有多层嵌套,需要在容器构件中operation()方法中递归调用成员构件的操作方法。

七、适配器模式

适配器模式:将一个类的接口转换为另一个接口,兼容新的新类。

使用适配器做个中转,将用户和被调用者解耦。

// MP4转为MP3格式
// 目标角色MP3
public class MP3{
    String getMP3(){
        return "MP3";
    }
}

//源角色MP4
public interface MP4{
    String getMP4();
}

// eg1 适配器Adapter,继承的依赖强,还可以使用聚合
public class MP4Adapter extends MP3 impl MP4{
    @Override
    public String getMP4(){
        return this.getMP3();
    }
}
// eg2
public class MP4Adapter impl MP4{
    private MP3 mp3;
    public MP4(MP3 mp3){
        this.mp3 = mp3;
    }
    @Override
    public String getMP4(){
        return mp3.getMP3();
    }
}

八、装饰者模式

装饰者模式动态地将责任附加到对象上。若要扩展功能,装置者提供了比继承更有弹性的替代方案。

主要角色:

抽象构件(Component):定义一个抽象接口以规范接收附加责任的对象。

具体构件(ConcreteComponent):实现抽象构件,通过装饰角色为其添加一些职责。

抽象装饰(Decorator):继承抽象构件,并包含具体构件的实例,可以通过其子类拓展具体构件的功能。

具体装饰(ConcreteDecorator):实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。

// 例:奶茶店买奶茶
// 抽象构件
public abstract class Tea{
    // 每种饮品的名称
    public String description = "就是白开水兑科技";
    private double price = 0.0f; 
    public String getDescription(){
        return description;
    }

    public double getPrice(){
        return price;
    }
    public void setDescription(String des){
        this.description = des;
    }
    public void setPrice(double price){
        this.price = price;
    }

    // 每种饮品的价格不同,定义为抽象方法
    public abstract double setPrice();
}

// 奶茶--具体构件
public class MilkTea extends Tea{
    public MilkTea(){
        setDescription("奶茶");
        setPrice(10);
    }

    @Override
    public double cost(){
        return super.getPrice();
    }
}

// 果茶--具体构件
public class FruitTea extends Tea{
    public FruitTea(){
        setDescription("果茶");
        setPrice(15);
    }

    @Override
    public double cost(){
        return super.getPrice();
    }
}

// 抽象装饰-继承抽象构件
public class materialDecorator extends Tea{
    // 装饰者聚合,关联一种饮品,以便附加新的行为
    private Tea tea;

    public material(Tea tea){
        this.tea = tea;
    }

    @Override
    public Double cost(){
        return getPrice() + tea.getPrice();
    }

    @Override
    public String getDescirption(){
        return des + ""+getPrice()+ ","+tea.getDescription();
    }
}

// 红豆-具体装饰
public class RedBean extends materialDecorator{
    public RedBean(Tea tea){
        super(tea);
        setDescription("红豆");
        setPrice(3);
    } 
}

// 椰果-具体装饰
public class Coconut extends materialDecorator{
    public Coconut(Tea tea){
        super(tea);
        setDescription("椰果");
        setPrice(5);
    } 
}

// 测试代码
public static main(String[] args){
    // 一杯奶茶
    Tea mt = new MilkTea();
    System.out.pritln("订单:"+ mt.getDescription()); // 奶茶
    System.out.pritln("订单费用:"+ mt.cost());  // 10
    // 奶茶加红豆
    Tea rb = new RedBean(mt);
    System.out.pritln("订单:"+ rb.getDescription()); // 奶茶,红豆
    System.out.pritln("订单费用:"+ rb.cost());   //13
    // 奶茶加红豆 + 椰果
    Tea cc = new Coconut(rb);
    System.out.pritln("订单:"+ cc.getDescription());// 奶茶,红豆,椰果
    System.out.pritln("订单费用:"+ cc.cost());   //18
}

九、状态模式--多用户登录态

状态模式(State Pattern):用以解决对象在多种状态转换时,需要对外输出不同行为的问题,状态和行为是一一对应的,状态之间可以相互转换。

当一个对象的内在状态改变时,允许改变其行为,这个对象看起来是改变了其类。

主要角色:

Context 环境角色:用于维护State实例,这个实例定义为当前状态。

State 抽象状态角色:定义一个接口封装与Context 的一个特点接口相关行为。

ConcreteState 具体状态角色:每个子类实现一个与Context 的一个状态相关行为。

会员阶梯:白银、黄金、铂金、砖石。不同会员得到不同对待。

// 对行为的抽象,若代码不需要,可不抽象。
public interface VipContext{
    void pays();
}

// 白银
public class SilverVipContext implements VipContext{
    private double price;
    
    public VipContextStatus(double price){
        this.price = price * 0.9;
    }
    
    @Overide
    public void pays(){
        System.out.println("白银VIP,享受折扣0.9,消费"+price);
    }
}

// 抽象状态角色
public class Card{
    VipContext vipContext;
    public void shopping(){
        vipContext.pays();
    }
    public void setVipContext(){
        this.status = status;
    }
}
// 测试代码
public static void main(String[] agrs){
    VipContext context = new SilverVipContext(1000);
    Card card = new card();
    card.setState(status);
    card.shopping();
}

十、享元模式

享元模式中的“享元”指被共享的单元,通过复用对象节省内存。

运用共享有效的支持大量细粒度的对象。

主要运用:在有大量对象时,有可能会造成内存溢出,把其中共同部分抽象出来,相同业务请求来时,直接返回内存中已有的对象,避免重新创建。

场景:系统中有大量对象;对象消耗大量内存;对象的状态可以外部化;这些对象可按照内蕴状态分为很多组,当把外蕴对象剥离出来,每一组都可用一个对象替代;系统不依赖这些对象身份,这些对象不可分辨。

解决思路:用唯一标识码判断,如果在内存中有,则返回这个唯一标识所标识的对象。

关键代码:用HashMap存储对象。

这些类必须有一个工厂对象加以控制。

原理:复用不可变的享元对象,通过工厂模式,使用Map或List缓存享元对象。

例:象棋游戏,游戏大厅可以开十万房间。每个房间差异只是棋子位置。

// 享元类
@AllArgsConstructor
@Getter
public class ChessPieceUnit{
    private int id;
    private String text;
    private Color color;
    private static enum Color {
        RED, BLACK;
    }
}

// 工厂类
public class ChessPieceUnitFactory{
    private static final Map<Integer, ChessPieceUnit> PIECES = new HashMap<>();
    static {
        PIECES.put(1, new ChessPieceUnit(1,"車", ChessPieceUnit.Color.BLACK));
        PIECES.put(2, new ChessPieceUnit(2,"马", ChessPieceUnit.Color.BLACK));
        ...
    }
    
    public static ChessPieceUnit getChessPiece(int chessPieceId){
        return PIECES.get(chessPieceId);
    }
}

// 具体棋局中的棋子
@AllArgsConstructor
@Data
public class NewChessPiece {
    private ChessPieceUnit chessPieceUnit;
    private int positionX;
    private int positionY;
}

// 棋局
public class NewChessBoard{
    private Map<Integer, NewChessPiece> chessPieces = new HashMap<>();
    public NewChessBoard(){ init(); }
    private void init() {
        chessPieces.put(1, new NewChessPiece(
            ChessPieceUnitFactory.getChessPiece(1),0,0));
        ...
    }
    public void move(int chessPieceId, int toPositionX, int toPositionY){
        // .....
    };
}

小结:

1、单例模式:目的是保证全局唯一,一个类只能创建一个对象。

2、享元模式:为实现对象复用,节省内存。

3、联想缓存:为提高访问效率,目的非复用。

4、使用享元模式,由于工厂类一直保存享元对象的引用,导致享元对象在无任何代码使用时,也不会被GC;使用前需验证享元模式是否能大省内存,是否适得其反。

未完待续,接设计模式理解(二)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值