【设计模式】2、创建型模式

1、创建型模式-工厂模式

⼯⼚模式也称简单⼯⼚模式,是创建型设计模式的⼀种,这种设计模式提供了按需创建对象的最佳⽅式。

同时,这种创建⽅式不会对外暴露创建细节,并且会通过⼀个统⼀的接⼝创建所需对象

工厂模式属于创建型模型的一种,其目的就是隐藏创建类的细节与过程。

(1)场景

我是一个准大一计算机专业学生,电脑小白,开学要买电脑,但是不懂电脑配置的任何相关信息,无从下手~

(2)未使用工厂模式

电脑接口:

public interface Computer {
	public String describe(); 
}

外星⼈游戏笔记本:

public class Alienware implements Computer{
	 @Override
	 public String describe() {
	 	return "外星⼈ALIENWARE m15 R7 15.6英⼨⾼端游戏本 12代i7 32G RTX3060 QHD 240Hz ⾼刷屏 轻薄笔记本电脑2765QB";
	 } 
 }

⾼性能独显PC主机:

public class Desktop implements Computer{
	 @Override
	 public String describe() {
		 return "外星⼈ALIENWARE R13 ⽔冷电竞游戏⾼端台式机 第12代i7 32G 512GB+2T RTX3070 办公台式机 9776W";
	 } 
 }

Macbook办公轻薄本:

public class Macbook implements Computer{
	 @Override
	 public String describe() {
	 	return "Apple MacBook Pro 13.3 ⼋核M1芯⽚ 8G 256G SSD 深空灰 笔记本电 脑 轻薄本 MYD82CH/A";
	 } 
 }

2U戴尔服务器:

public class Server implements Computer{
	 @Override
	 public String describe() {
		 return "戴尔(DELL) R740⼁R750⼁2U机架式服务器主机双路GPU深度学习 R740〖1 *银牌4210R 10核20线程〗 8G内存⼁1TB SATA硬盘 ⼁H350戴尔(DELL)";
	 } 
 }

以上分析,所有电脑放在店里,顾客进店后只知道自己的需求,不知道店里各种规格和型号的电脑哪个适合自己,这种需要让客户自己了解细节才能决定结果的,从设计层面上讲就破坏了“迪米特法则”,抉择权应该在电脑店,而不是顾客自己手里,目前的电脑和顾客的关系图就如下所示,顾客知道的太多,不能够做出抉择:

在这里插入图片描述

(3)使用工厂模式

这个时候我们需要一个工厂类,让顾客只知道自己的需求,不用了解电脑的规格和参数就能选出一个参考的电脑来
在这里插入图片描述
增加一个导购员帮助用户实现抉择,根据用户的不同需求提供不同的电脑产品,这就相当于隐藏了用户对电脑配置和规格的抉择,只需要关注自己的需求即可完成电脑的选择。

「3.1」代码实现

导购员就充当了“工厂”的角色:

public class ShopAssistant {
	 public Computer suggest(String purpose){
		 Computer computer = null;
		 if(purpose.equals("⽹站建设")){
		 	return new Server();
		 }else if(purpose.equals("电竞⽐赛")){
		 	return new Desktop();
		 }else if(purpose.equals("⽇常办公")){
		 	return new Macbook();
		 }else if(purpose.equals("3A游戏")){
		 	return new Alienware();
		 }
		 return computer;
	 } 
 }

此时用户只关注自己的需求,将其告诉导购员即可获取对应推荐的电脑:

public class Customer {
	 public static void main(String[] args) {
	 	 List<String> purposes = Arrays.asList("网站建设", "电竞比赛", "日常办公","3A游戏");
         //随机获取业务名称,模拟顾客需求
         String purpose = purposes.get((int) (Math.random() * 4));

		 ShopAssistant shopAssistant = new ShopAssistant();
		 Computer c = shopAssistant.suggest(purpose);
		 System.out.println(c.describe());
	 } 
 }

工厂就是通过if…else来创建对象,当然对于if…else也可以进行优化,例如使用反射或者初始化就不用多层if…else。

总之工厂的特点就是:提供方法根据需求来返回结果。

使用反射和初始化完成形状工厂例子:

public interface ShapeFactory {

	//多例对象
    enum SHAPEUTILS {

        CIRCLE(Circle.class),
        DIAMOND(Diamond.class);

        public Class shapeClass;

        SHAPEUTILS(Class shapeClass) {
            this.shapeClass = shapeClass;
        }

        /**
         * 通过形状编码获取指定形状的新类
         *
         * @param shapeClass shape接口的子类字节码类
         * @return 形状接口实例对象
         */
        public static Shape getShapeByShapeClass(Class shapeClass) {
            try {
                return (Shape) shapeClass.newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

	//单例对象
    enum ShapeFactoryUtils {

        CIRCLE("CIRCLE", new Circle()),
        DIAMOND("DIAMOND", new Diamond());

        public String shapeCode;
        public Shape shape;
        public static Map<String, Shape> shapeLookup = new HashMap<>();

        ShapeFactoryUtils(String shape, Shape shapeClass) {
            this.shapeCode = shape;
            this.shape = shapeClass;
        }

        static {
            for (ShapeFactoryUtils shape : ShapeFactoryUtils.values()) {
                shapeLookup.put(shape.shapeCode, shape.shape);
            }
        }

        /**
         * 通过形状编码获取指定形状的新类
         *
         * @param shapeCode 形状编码
         * @return 指定形状类
         */
        public static Shape getShapeByShapeCode(String shapeCode) {
            return shapeLookup.get(shapeCode);
        }
    }
}

「3.2」项目中的应用

例如可销售给不同地区、国家的项目,可能需要不同语言来显示系统字体,是需要让用户自己选择字体然后登陆系统?

这样以来Client就知道系统国际化的细节,知道有支持多少种语言,也是违背“迪米特法则”的,所以可以用“工厂模式”进行改进。
在这里插入图片描述
还是通过改进自动识别?
在这里插入图片描述

2、创作型模式-抽象工厂模式

通过构建顶层的抽象⼯⼚和抽象的产品,屏蔽系列产品的构建过程。

抽象工厂其实很好理解,它其实就是其他工厂的工厂,它可以在抽象工厂中创建出其他工厂,与工厂模式一样,都是来解决接口选择问题,同样属于创建型模式。

(1)场景

公司的一个项目早期接入七牛云OSS上传图片与视频,后来因为业务调整,公司要求额外支持阿里云、腾讯云等其他云服务商,并且可以对客户提供外界访问。

(2)代码实现

任何OSS对外提供的功能基本上是一样的,但是针对每个厂商可能有自己的特色,例如七牛云是免费的,但是针对于图片或视频提供的清晰度优化并不高,像阿里云、腾讯云等等OSS是付费的,就可以为提供优化为更高清晰度的图片和视频。

「2.1」公共抽象

使用抽象工厂将都具备的功能给抽象出来,构建顶层的抽象⼯⼚和抽象的产品,隐藏具体实现细节。

图片接口:

public interface OssImage {

    /**
     * 获取缩略图
     * @return 展示地址
     */
    String getThumb();

    /**
     * 获取带的水印图片
     * @return 展示地址
     */
    String getWatermark();

    /**
     * 获取增强清晰度的图片
     * @return 展示地址
     */
    String getEnhance();
}

视频接口:

public interface OssVideo {

    /**
     * 获取高清视频
     * @return 播放地址
     */
    String get720P();

    /**
     * 获取2k视频
     * @return 播放地址
     */
    String get1080P();
}

抽象工厂:

public interface AbstractOssFactory {

    /**
     * 上传图片
     *
     * @param bytes 图片
     * @return 展示地址
     */
    OssImage uploadImage(byte[] bytes);

    /**
     * 上传视频
     *
     * @param bytes 视频
     * @return 播放地址
     */
    OssVideo uploadVideo(byte[] bytes);
}

「2.2」产品细节实现

不同的产品,实现细节是不同的,例如阿里云和七牛云的图片缩略图的尺寸默认生产尺寸不同、阿里云额外支持图片透明背景、更清晰的图片和更高码率的视频,而通过对工厂产品的封装,再将产品交给工厂,用户直接使用工厂即可,并不用关心产品实现细节。

阿里云上传图片细节实现:

public class AliyunOssImage implements OssImage {

    private byte[] bytes;

    /**
     * 阿里云上传图片实现细节
     *
     * @param bytes       图片
     * @param watermark   水印内容
     * @param transparent 是否生成透明背景
     */
    public AliyunOssImage(byte[] bytes, String watermark, boolean transparent) {
        this.bytes = bytes;
		
		//模拟上传成功
        System.out.println("[阿⾥云]图⽚已上传⾄阿⾥云OSS,URL:http://oss.aliyun.com/xxxxxxx.jpg");
        System.out.println("[阿⾥云]已⽣成缩略图,尺⼨640X480像素");
        System.out.println("[阿⾥云]已为图⽚新增⽔印,⽔印⽂本:" + watermark + ",⽂本颜⾊:#aaaaaa,背景透明:" + transparent);
        System.out.println("[阿⾥云]已将图⽚AI增强为4K极清画质");
    }

	//模拟上传成功后返回的地址
    @Override
    public String getThumb() {
        return "http://oss.aliyun.com/xxxxxxx_thumb.jpg";
    }

	//模拟上传成功后返回的地址
    @Override
    public String getWatermark() {
        return "http://oss.aliyun.com/xxxxxxx_watermark.jpg";
    }

	//模拟上传成功后返回的地址
    @Override
    public String getEnhance() {
        return "http://oss.aliyun.com/xxxxxxx_enhance.jpg";
    }
}

阿里云上传视频细节实现:

public class AliyunOssVideo implements OssVideo {

    private byte[] bytes;

    /**
     * 阿里云上传视频实现细节
     * @param bytes 视频
     * @param watermark 水印内容
     */
    public AliyunOssVideo(byte[] bytes, String watermark) {
        this.bytes = bytes;

        //模拟上传视频成功
        System.out.println("[阿⾥云]视频已上传⾄阿⾥云OSS,URL:http://oss.aliyun.com/xxx.mp4");
        System.out.println("[阿⾥云]720P转码成功,码率:5000K");
        System.out.println("[阿⾥云]1080P转码成功,码率:7000K");
    }

    //模拟上传成功后返回的地址
    @Override
    public String get720P() {
        return "http://oss.aliyun.com/xxx_720p.mp4";
    }
    
    //模拟上传成功后返回的地址
    @Override
    public String get1080P() {
        return "http://oss.aliyun.com/xxx_1080p.mp4";
    }
}

七牛云上传图片实现细节:

public class QiniuOssImage implements OssImage {

    private byte[] bytes;

    /**
     * 七牛云上传图片实现细节
     * @param bytes 图片
     * @param watermark 水印内容
     */
    public QiniuOssImage(byte[] bytes, String watermark) {
        this.bytes = bytes;

        //模拟上传成功
        System.out.println("[七⽜云]图⽚已上传⾄七⽜云OSS,URL:http://oss.qini u.com/xxxxxxx.jpg");
        System.out.println("[七⽜云]已⽣成缩略图,尺⼨800X600像素");
        System.out.println("[七⽜云]已为图⽚新增⽔印,⽔印⽂本:" + watermark + ",⽂本颜⾊#cccccc");
        System.out.println("[七⽜云]已将图⽚AI增强为1080P⾼清画质");
    }

    //模拟上传成功后返回的地址
    @Override
    public String getThumb() {
        return "http://oss.qiniu.com/xxxxxxx_thumb.jpg";
    }

    //模拟上传成功后返回的地址
    @Override
    public String getWatermark() {
        return "http://oss.qiniu.com/xxxxxxx_watermark.jpg";
    }

    //模拟上传成功后返回的地址
    @Override
    public String getEnhance() {
        return "http://oss.qiniu.com/xxxxxxx_enhance.jpg";
    }
}

七牛云上传视频实现细节:

public class QiniuOssVideo implements OssVideo {

    private byte[] bytes;

    /**
     * 七牛云上传视频实现细节
     * @param bytes 视频
     * @param watermark 水印内容
     */
    public QiniuOssVideo(byte[] bytes, String watermark) {
        this.bytes = bytes;
        System.out.println("[七⽜云]视频已上传⾄阿⾥云OSS,URL:http://oss.qiniu.com/xxx.mp4");
        System.out.println("[七⽜云]720P转码成功,码率:2500K");
        System.out.println("[七⽜云]1080P转码成功,码率:3500K");
    }

    //模拟上传成功后返回的地址
    @Override
    public String get720P() {
        return "http://oss.qiniu.com/xxx_720p_2500.mp4";
    }

    //模拟上传成功后返回的地址
    @Override
    public String get1080P() {
        return "http://oss.qiniu.com/xxx_1080p_3500.mp4";
    }
}

「2.3」工厂实现

通过实现抽象工厂创造出不同的工厂,来提供不同的实现方法,工厂方法来进行细节的实现。

阿里云OSS工厂:

public class AliyunOssFactory implements AbstractOssFactory {

    /**
     * 上传图片
     *
     * @param bytes 图片
     * @return 展示链接
     */
    @Override
    public OssImage uploadImage(byte[] bytes) {
        return new AliyunOssImage(bytes, "抽象工厂模式", true);
    }

    /**
     * 上传视频
     *
     * @param bytes 视频
     * @return 播放链接
     */
    @Override
    public OssVideo uploadVideo(byte[] bytes) {
        return new AliyunOssVideo(bytes, "抽象工厂模式");
    }

}

七牛云OSS工厂:

public class QiniuOssFactory implements AbstractOssFactory {

    /**
     * 上传图片
     * @param bytes 图片
     * @return 展示地址
     */
    @Override
    public OssImage uploadImage(byte[] bytes) {
        return new QiniuOssImage(bytes, "抽象工厂模式");
    }

    /**
     * 上传视频
     * @param bytes 视频
     * @return 播放地址
     */
    @Override
    public OssVideo uploadVideo(byte[] bytes) {
        return new QiniuOssVideo(bytes, "抽象工厂模式");
    }

}

「2.4」业务代码使用OSS工厂

可以看到,通过抽象工厂对OSS的顶层产品进行抽象,具体产品工厂实现抽象工厂,不同细节对于抽象工厂是隐藏的,在使用时我们只关系使用的是哪个产品工厂,即可完成相应功能的实现,但是不同的工厂的产品特质可能也不同(例如不同清晰度的图片和不同码率的视频等)。

public class AbstractOssFactoryTest {

    public static void main(String[] args) {
        AbstractOssFactory factory = new QiniuOssFactory();

        OssImage ossImage = factory.uploadImage(new byte[1024]);
        OssVideo ossVideo = factory.uploadVideo(new byte[1024]);
        
        System.out.println(ossImage.getThumb());
        System.out.println(ossImage.getWatermark());
        System.out.println(ossImage.getEnhance());
        System.out.println(ossVideo.get720P());
        System.out.println(ossVideo.get1080P());

        System.out.println("===========================================");

        AbstractOssFactory factory2 = new AliyunOssFactory();
        
        OssImage ossImage2 = factory2.uploadImage(new byte[1024]);
        OssVideo ossVideo2 = factory2.uploadVideo(new byte[1024]);
        
        System.out.println(ossImage2.getThumb());
        System.out.println(ossImage2.getWatermark());
        System.out.println(ossImage2.getEnhance());
        System.out.println(ossVideo2.get720P());
        System.out.println(ossVideo2.get1080P());
    }
}

即使以后仍要对接其他)SS厂商,我们只关系其他OSS服务的实现细节,然后创建工厂实现抽象工厂,即可完成OSS的对接服务。这就符合“开闭原则”,针对于原有类、对象、模块、函数等的扩展是开放的,并没有去进行修改。

3、创造型模式-单例模式

//TODO

4、创造型模式-构建者模式

//TODO

5、创造型模式-原型模式

//TODO

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值