美文网首页
对于JAVA设计模式的自我修养

对于JAVA设计模式的自我修养

作者: 小明同学机器人 | 来源:发表于2021-05-29 18:28 被阅读0次

    对于JAVA设计模式的自我修养

    一 、工厂模式

    这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

    1. 抽象工厂模式

    抽象工厂模式(Abstract Factory),提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

    抽象工厂模式中,此例为A和B两家工厂,都生产小汽车和船,需要哪个工厂的船或者车子,在AFactoryThing 或者BFactoryThing中生产所需要的东西即可

    类图

    image-20210527103006439.png

    案例设计思路

    1. 创建一个工厂接口包含A和B工厂生产的方法,返回值为A中产品的父类,即满足无需指定它们具体的类。
    2. 创建A、B工厂并实现1中的接口 ,A中生产A产品,若A生产B则非法权限,B反之
    3. 创建A、B两工厂的自营店,分别继承AB工厂,实现AB工厂的规章制度,变量和方法
    4. 最后将写入自己工厂的产品类,继承自己的自营店。

    代码案例

    public interface AbstractCreateFactory {
        AFactoryThing createAFactoryThing(int id);
        BFactoryThing createBFactoryThing(int id);
    
    }
    public class AFactoryThing  extends ProduceAFactory{
        public int price = 0;
        public String name = "A";
    
        public void toProduce() {
            System.out.println("这是我们A公司的" + name + "\t价格为" + price);
        }
    //从超市买东西,超市自己从商店买东西
    }
    public  class BFactoryThing extends  ProduceBFactory {
        public int price = 0;
        public String name = "B";
    
        public void toProduce() {
            System.out.println("这是我们B公司的" + name + "\t价格为" + price);
        }
        
    }
    public class CarA extends AFactoryThing {
        public CarA() {
            price=9;
            name="车子";
            toProduce();
        }
    }
    public class CarB extends BFactoryThing {
        public CarB() {
            name = "车子";
            price = 10;
            toProduce();
        }
    }
    
    public class ProduceAFactory implements AbstractCreateFactory {
        @Override
        public AFactoryThing createAFactoryThing(int id) {
            AFactoryThing aFactoryThing = null;
            switch (id) {
                case 0:
                    aFactoryThing = new CarA();
                    break;
                case 1:
                    aFactoryThing = new ShipA();
    
                    break;
                default:
                    aFactoryThing = new CarA();
                    break;
            }
    
            return aFactoryThing;
        }
    
        @Override
        public BFactoryThing createBFactoryThing(int id) {
            System.out.println("A工厂没有权限生产B产品");
            return null;
    
        }
    }
    public class ProduceBFactory implements AbstractCreateFactory {
        @Override
        public AFactoryThing createAFactoryThing(int id) {
            System.out.println("B工厂没有权限生产A产品");
           return  null;
        }
    
        @Override
        public BFactoryThing createBFactoryThing(int id) {
            BFactoryThing bFactoryThing=null;
    
            switch (id) {
                case 0:
                    bFactoryThing=new CarB();
                    break;
                case 1:
                    bFactoryThing=new ShipB();
                    break;
                default:
                    bFactoryThing=new CarB();
    
                    break;
            }
            return bFactoryThing;
        }
    }
    public class ShipA extends AFactoryThing {
    
    
        public ShipA() {
            price = 19;
            name = "船";
            toProduce();
        }
    
    }
    public class ShipB extends BFactoryThing {
    
        public ShipB() {
            price = 20;
            name = "船";
            toProduce();
        }
    }
    public class Client {
        public static void main(String[] args) {
            AFactoryThing aFactoryThing = new AFactoryThing();
            BFactoryThing bFactoryThing = new BFactoryThing();
            aFactoryThing.createAFactoryThing(0);
            aFactoryThing.createAFactoryThing(1);
            bFactoryThing.createBFactoryThing(0);
            ShipB bFactoryThing1 = (ShipB)bFactoryThing.createBFactoryThing(1);
        }
    }
    
    
    

    2. 简单工厂模式

    类图

    image-20210527103111402.png
    • 我们把被创建的对象称为“产品”,把创建产品的对象称为“工厂”。如果要创建的产品不多,只要一个工厂类就可以完成,这种模式叫“简单工厂模式”。

    案例设计思路

    简单工厂模式的创作思路就更简单了,工厂接口类,本例中用到了操作类工厂,返回自己需要的类型即可

    代码案例

    public interface AbstractCalculateFactory {
        OperationCal createOperationCal(String message);
    }
    public class AddCalculate extends OperationCal {
        public  AddCalculate() {
            message=add;
            result = x + y;
            showResult();
        }
    }
    public class DivCalculate extends OperationCal {
        public DivCalculate() {
            message = div;
            result = x / y;
            showResult();
        }
    }
    public class MulCalculate extends  OperationCal{
        public  MulCalculate() {
            message=mul;
            result = x * y;
          showResult();
        }
    }
    public class ReduceCalculate extends OperationCal {
        public ReduceCalculate() {
            message = red;
            result = x - y;
            showResult();
        }
    }
    public class OperationCal implements AbstractCalculateFactory {
        public double x = 16;
        public double y = 8;
        public double result = 0;
        public String message = "";
        public static String add="ADD";
        public static String red="RED";
        public static String mul="MUL";
        public static String div="DIV";
        @Override
        public OperationCal createOperationCal(String message) {
    
            OperationCal operationCal = null;
            switch (message) {
                case "add":
                    operationCal = new AddCalculate();
                    break;
                case "red":
                    operationCal = new ReduceCalculate();
                    break;
                case "mul":
                    operationCal = new MulCalculate();
                    break;
                case "div":
                    operationCal = new DivCalculate();
                    break;
                default:
                    operationCal = new DivCalculate();
                    System.out.println("操作有误");
            }
    
            return operationCal;
        }
    
        public void showResult() {
            System.out.println(x + message + y + "的结果为" + result + "\n");
        }
    }
    
    public class OperationClient {
        public static void main(String[] args) {
          OperationCal operationCal=new OperationCal();
          operationCal.createOperationCal("div");
          operationCal.createOperationCal("mul");
          operationCal.createOperationCal("add");
          operationCal.createOperationCal("red");
    
        }
    }
    
    

    二、建造者模式

    建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

    类图

    image-20210527103217571.png

    抽象类实现接口后 不用实现接口的所有方法 ,非抽象类就得实现接口的所有方法

    普通类继承抽象类后,得重写实现抽象类未实现的方法!

    案例设计思路

    1. 本实例中创建了Item(商品类目)和Packing(打包) 的接口,Item描述了name,packing和price方法,Packing描述了pack方法

    2. 实现接口 注意 Item(商品类目)包含Burger(汉堡)和ColdDrink(冷饮)两个抽象类 (注意为何写抽象类,抽象类中的price()方法可以忽略,那是一个抽象方法,不是实现Item中的price方法)所以抽象类只实现了packing方法,剩下两个方法在子类中实现的.(层层搭建)

    3. 瓶装和袋装两个类实现Packing接口,实体类封装搭建完毕之后开始管理类的搭建

    4. 做菜单管理类 meal ,添加商品(添加商品直接为item对象,不管是点什么菜品都加入其中即可),计算价钱,返回商品

    5. 最后MealBuilder 菜单建造者类 相当于客人点菜类,点好菜后,Meal 返回。

    代码案例

    package com.example.xm.build;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public interface Item {
        public String name();
        public Packing packing();
        public float price();
    }
    interface Packing {
        public String pack();
    }
     class Wrapper implements Packing {
    
        @Override
        public String pack() {
            return "Wrapper";
        }
    }
     class Bottle implements Packing {
    
        @Override
        public String pack() {
            return "Bottle";
        }
    }
    abstract class Burger implements Item {
    
        @Override
        public Packing packing() {
            return new Wrapper();
        }
    
    
        @Override
        public abstract float price();
    }
    abstract class ColdDrink implements Item {
    
        @Override
        public Packing packing() {
            return new Bottle();
        }
    
        @Override
        public abstract float price();
    }
    class VegBurger extends Burger {
        @Override
        public String name() {
            return "Veg Burger";
        }
    
        @Override
        public float price() {
            return 0;
        }
    }
    class ChickenBurger extends Burger {
    
        @Override
        public float price() {
            return 50.5f;
        }
    
        @Override
        public String name() {
            return "Chicken Burger";
        }
    }
    class Coke extends ColdDrink {
    
        @Override
        public float price() {
            return 30.0f;
        }
    
        @Override
        public String name() {
            return "Coke";
        }
    }
    class Pepsi extends ColdDrink {
    
        @Override
        public float price() {
            return 35.0f;
        }
    
        @Override
        public String name() {
            return "Pepsi";
        }
    }
    class Meal {
        private List<Item> items = new ArrayList<Item>();
    
        public void addItem(Item item){
            items.add(item);
        }
    
        public float getCost(){
            float cost = 0.0f;
            for (Item item : items) {
                cost += item.price();
            }
            return cost;
        }
    
        public void showItems(){
            for (Item item : items) {
                System.out.print("Item : "+item.name());
                System.out.print(", Packing : "+item.packing().pack());
                System.out.println(", Price : "+item.price());
            }
        }
    }
    class MealBuilder {
        public Meal prepareVegMeal (){
            Meal meal = new Meal();
            meal.addItem(new VegBurger());
            meal.addItem(new Coke());
            return meal;
        }
    
        public Meal prepareNonVegMeal (){
            Meal meal = new Meal();
            meal.addItem(new ChickenBurger());
            meal.addItem(new Pepsi());
            return meal;
        }
    }
    class BuilderPatternDemo {
        public static void main(String[] args) {
            MealBuilder mealBuilder = new MealBuilder();
    
            Meal vegMeal = mealBuilder.prepareVegMeal();
            System.out.println("Veg Meal");
            vegMeal.showItems();
            System.out.println("Total Cost: " +vegMeal.getCost());
    
            Meal nonVegMeal = mealBuilder.prepareNonVegMeal();
            System.out.println("\n\nNon-Veg Meal");
            nonVegMeal.showItems();
            System.out.println("Total Cost: " +nonVegMeal.getCost());
        }
    }
    

    三、原型模式

    原型模式是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。(通过克隆返回对象)

    这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。(缓存对象,克隆返回对象)

    类图

    image-20210527103238348.png

    原型模式中设计思路 加载缓存返回缓存对象

    案例设计思路

    1. 代码以加载图形和缓存为案例,创建三种图形类(相当于数据库的操作)
    2. 然后将图形加入到缓存中,ShapeCache 中的loadCache方法
    3. 其次再用getShape(id) 返回所需要的图形对象

    原型模式的优点就是高性能,需要某个对象的时候能够快速的构建出来

    另外 原型模式可逃避构造函数的约束。不需要new 的方式构建新对象

    代码案例

    public abstract class Shape implements Cloneable {
        private String id;
        protected  String type="默认";
        abstract void draw();
        public String getType() {
            return type;
        }
        public void setId(String id) {
            this.id = id;
        }
        public String getId() {
            return id;
        }
        @Override
        protected Object clone() {
            Object clone = null;
            try {
                clone = super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return clone;
        } 
    }
    
    public class Circle extends Shape {
    
        public Circle() {
            type = "圆";
        }
        @Override
        void draw() {
            System.out.println("画了一个" + type);
        }
    }
    
    public class Rectangle extends Shape {
        public Rectangle() {
            type = "Rectangle";
        }
        @Override
        void draw() {
            System.out.println("画了一个"+type);
        }
    }
    
    public class Square extends Shape {
        public Square() {
            type = "Square";
        }
        @Override
        void draw() {
            System.out.println("画了一个"+type);
        }
    }
    
    public class ShapeCache { //形状缓存区
        private static Hashtable<String, Shape> shapeMap = new Hashtable<String, Shape>();
    
        //读取形状
         public static Shape getShape(String shapeId) {
            Shape cache = shapeMap.get(shapeId);
            return (Shape) cache.clone();
    
        }
         public static void loadCache() {
            Circle circle = new Circle();
            circle.setId("1");
    
            Square square = new Square();
            square.setId("2");
    
            Rectangle rectangle = new Rectangle();
            rectangle.setId("3");
            shapeMap.put(circle.getId(), circle);
            shapeMap.put(square.getId(), square);
            shapeMap.put(rectangle.getId(), rectangle);
        }
    }
    
    public class PrototypeClient {
        public static void main(String[] args) {
            ShapeCache.loadCache(); //加载缓存
            Shape shape = ShapeCache.getShape("1");
          shape.draw();
            Shape shape1 = ShapeCache.getShape("2");
            shape1.draw();
            Shape shape2 = ShapeCache.getShape("3");
            shape2.draw();
        }
    }
    

    四、适配器模式

    适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。

    这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能。

    适配器是什么,先从宏观上生活上,它就是一个用来适配某个东西来达到某种效果的一个物体,起到一个转换作用或者是红线作用

    例子:本例子遵循菜鸟教程例子:有一个音频播放器,但是只支持mp3格式的播放,然后做了一个适配器,将音频播放器和适配器连接,播放mp4和vlc的音频,所以再音频播放器里直接调用适配器即可

    类图

    image-20210527113237917.png

    案例设计思路

    1. 适配器模式的代码对菜鸟做了略微的修改,修改后相对于原先更美观,更简洁
    2. 首先建立一个接口AdvanceMediaPlayer ,用mp4和vlc 两个类实现
    3. 然后建立一个适配器MediaAdapter,实现播放mp4和vlc为文件
    4. 最后将原始播放器拿过来继承适配器,这样原来的播放器就会支持本来的mp3和现有的mp4,vlc文件
    5. 最后Client 将需要的文件播放

    代码案例

    
    public interface AdvanceMediaPlayer {
        void playVlc(String fileName);
        void playMp4(String fileName);
    }
    
    public interface MediaPlayer {
        void play(String audioTYpe,String fileName);
    }
    
    public class Mp4Player implements AdvanceMediaPlayer {
    
        @Override
        public void playVlc(String fileName) {
            System.out.println("文件不匹配");
        }
    
        @Override
        public void playMp4(String fileName) {
            System.out.println("播放了Mp4" + fileName);
    
        }
    }
    
    public class VlcPlayer implements AdvanceMediaPlayer {
        @Override
        public void playVlc(String fileName) {
            System.out.println("播放了VLC"+fileName);
        }
    
        @Override
        public void playMp4(String fileName) {
            System.out.println("文件不匹配");
        }
    }
    
    public class MediaAdapter implements MediaPlayer {
        private AdvanceMediaPlayer advanceMediaPlayer;
    
        public void prepareAudio(String audioType) {
    
            if (audioType.equalsIgnoreCase("vlc")) {
                advanceMediaPlayer = new VlcPlayer();
            } else if (audioType.equalsIgnoreCase("mp4")) {
                advanceMediaPlayer = new Mp4Player();
            }
    
        }
    
    
        @Override
        public void play(String audioType, String fileName) {
            if (audioType.equalsIgnoreCase("vlc")) {
                advanceMediaPlayer.playVlc(fileName);
            } else if (audioType.equalsIgnoreCase("mp4")) {
                advanceMediaPlayer.playMp4(fileName);
            }
        }
    }
    
    public class AudioPlay extends MediaAdapter{
    
        public AudioPlay() {
        }
    
        @Override
        public void play(String audioTYpe, String fileName) {
            if (audioTYpe.equalsIgnoreCase("vlc") || audioTYpe.equalsIgnoreCase("mp4")) {
                super.prepareAudio(audioTYpe);
                super.play(audioTYpe, fileName);
            } else if (audioTYpe.equalsIgnoreCase("mp3")) {
                System.out.println("播放mp3");
            } else {
                System.out.println("不支持该文件");
            }
        }
    }
    
    public class AdapterClient {
        public static void main(String[] args) {
            AudioPlay audioPlayer = new AudioPlay();
            audioPlayer.play("vlc","java.vlc");
            audioPlayer.play("mp4","java.mp4");
            audioPlayer.play("mp3","java.mp3");
            audioPlayer.play("m","java.m");
        }
    }
    

    五、桥接模式

    桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。

    类图

    image-20210529124751423.png

    案例设计思路

    1. 桥接模式抽象类调用接口,实现代码独立通过抽象类来聚合接口,调用抽象类的子类,完成程序
    2. 定义好DrawApi 接口类,并用绿圆和红圆实现接口
    3. 再定义图形Shape类,聚合接口类,构造传参数,并抽象一个draw的方法
    4. 最后定义Circle类,继承Shape,实现draw方法,该方法里聚合接口类的方法,完成桥接模式。

    代码案例

    interface  DrawApi {
        void drawCircle();
    }
    
    public class RedCircle  implements  DrawApi{
        @Override
        public void drawCircle() {
            System.out.println("画了一个红色的圆");
        }
    }
    
    public class GreenCircle  implements  DrawApi{
        @Override
        public void drawCircle() {
            System.out.println("画了一个绿色的圆");
    
        }
    }
    
    public abstract class Shape {
        public DrawApi drawApi;
    
        public Shape(DrawApi drawApi) {
            this.drawApi = drawApi;
        }
        abstract void draw();
    }
    
    public class Circle extends Shape {
        public Circle(DrawApi drawApi) {
            super(drawApi);
        }
    
        @Override
        void draw() {
           drawApi.drawCircle();
        }
    }
    
    public class BridgeClient {
        public static void main(String[] args) {
            RedCircle redCircle = new RedCircle();
            GreenCircle greenCircle = new GreenCircle();
            Shape circle = new Circle(redCircle);
            Shape circle1 = new Circle(greenCircle);
            circle.draw();
            circle1.draw();
        }
    }
    

    六、单例模式

    单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。

    这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。1.

    懒汉式,线程不安全

    public class LazySingle {
        private static LazySingle lazySingle;
    //调用实例方法时候再判断是否存在实例对象,线程不安全,操作不规范可能创建多个对象
        public static LazySingle getInstance() {
            if (lazySingle == null) {
                lazySingle = new LazySingle();
            }
            return lazySingle;
        }
    }
    

    懒汉式,线程安全

    public class LazySingleSafe {
        private static LazySingleSafe lazySingleSafe;
    
        public static synchronized LazySingleSafe getInstance() {
    //调用实例方法时候再判断是否存在实例对象,只不过方法加了个线程锁,防止多个线程同时进入
            if (lazySingleSafe == null) {
                lazySingleSafe = new LazySingleSafe();
            }
            return lazySingleSafe;
        }
    }
    

    饿汉式

    public class HungrySingle {
        private static HungrySingle hungrySingle = new HungrySingle();
    //先加载创建好对象后,调用实例方法直接返回静态对象
        public static HungrySingle getInstance() {
            return hungrySingle;
        }
    
    }
    

    双检锁/双重校验锁

    public class DoubleCheckSingle {
        private static DoubleCheckSingle doubleCheckSingle;
    //内部类 利用类加载器机制,进行同步锁,指挥加载一次,不会同时进入线程锁里面
        public DoubleCheckSingle getInstances() {
            if (doubleCheckSingle == null) {
                synchronized (DoubleCheckSingle.class) {
                    if (doubleCheckSingle == null) {
                        doubleCheckSingle = new DoubleCheckSingle();
                    }
                    
                }
    
            }
            return doubleCheckSingle;
        }
    
    }
    

    登记式/静态内部类

    //内部类方式的单例模式
    public class StaticSingle {
        private static class StaticSingleHolder {
            private static StaticSingle single = new StaticSingle();
        }
    //这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,
    // 应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,
    // 双检锁方式可在实例域需要延迟初始化时使用。
        public StaticSingle getInstance() {
    
            return StaticSingleHolder.single;
        }
    }
    

    枚举

    public enum EchoSingle {
        INSTANCE;
    }
    //枚举机制的单例
    class Client {
        public static void main(String[] args) {
            EchoSingle echoSingle = EchoSingle.INSTANCE;
    
        }
    }
    

    相关文章

      网友评论

          本文标题:对于JAVA设计模式的自我修养

          本文链接:https://www.haomeiwen.com/subject/ixuklltx.html