常用的面向过程风格的代码|设计模式基础(一)

简介: 在Java开发中,我们实际上会利用Java这种面向对象语言,在无意中写出很多面向过程风格的代码。

在Java开发中,我们实际上会利用Java这种面向对象语言,在无意中写出很多面向过程风格的代码。

譬如我们违背了面向对象的 三大特性 ,违背了面向对象的定义,这样子的代码都会变成面向过程风格的代码。

下面列举三种面向过程风格的代码

gettersetter 未作封装

public class ShoppingCart {
  private int itemsCount;
  private double totalPrice;
  private List<ShoppingCartItem> items = new ArrayList<>();
  public int getItemsCount() {
    return this.itemsCount;
  }
  public void setItemsCount(int itemsCount) {
    this.itemsCount = itemsCount;
  }
  public double getTotalPrice() {
    return this.totalPrice;
  }
  public void setTotalPrice(double totalPrice) {
    this.totalPrice = totalPrice;
  }
  public List<ShoppingCartItem> getItems() {
    return this.items;
  }
  public void addItem(ShoppingCartItem item) {
    items.add(item);
    itemsCount++;
    totalPrice += item.getPrice();
  }
}
复制代码

例如上述的代码,gettersetter 未作任何封装,数据没有访问权限,可以随意被修改。可见该代码违背面向对象中封装的定义,其为一段面向过程风格的代码。

那么,如何利用封装的特性,将其改为一段 面向对象 风格的代码呢?

首先我们去除所有的 setter 方法,使其不与 addItem(ShoppingCartItem item) 起冲突,即只留 addItem 这一个修改数据的通道。这样子也许你会认为代码已封装完毕,数据已不会再被其他的方法随意修改了。

但事实上,这样子还是没有封装好,我们的数据依旧会被修改。我们可以这样子操作:

public static void main(String[] args) {
    ShoppingCartItem item1,item2;
    item1 = new ShoppingCartItem("no1",19);
    item2 = new ShoppingCartItem("no2",30);
    ShoppingCart cart = new ShoppingCart();
    cart.addItem(item1);
    cart.addItem(item2);
    cart.getItems().clear();//清空list,但是总价格,总数量未改变。封装不彻底
    System.out.println(cart.getTotalPrice());
}
复制代码

上述的代码还是会在我们的设计的方法之外随意改变我们的数据,且导致数据不同步、出错

我们需要借用Collections.unmodifiableList() 方法,做到彻底的封装。

public List<ShoppingCartItem> getItems() {
  return Collections.unmodifiableList(this.items);
}
复制代码

我们查看一下 Collections.unmodifiableList() 的源码,就可知道为何这样子可以防止修改了。

public static <T> List<T> unmodifiableList(List<? extends T> list) {
        return (list instanceof RandomAccess ?
                new UnmodifiableRandomAccessList<>(list) :
                new UnmodifiableList<>(list));
    }
    /**
     * @serial include
     */
    static class UnmodifiableList<E> extends UnmodifiableCollection<E>
                                  implements List<E> {
        @java.io.Serial
        private static final long serialVersionUID = -283967356065247728L;
        @SuppressWarnings("serial") // Conditionally serializable
        final List<? extends E> list;
        UnmodifiableList(List<? extends E> list) {
            super(list);
            this.list = list;
        }
        public boolean equals(Object o) {return o == this || list.equals(o);}
        public int hashCode()           {return list.hashCode();}
        public E get(int index) {return list.get(index);}
        public E set(int index, E element) {
            throw new UnsupportedOperationException();
        }
        public void add(int index, E element) {
            throw new UnsupportedOperationException();
        }
        public E remove(int index) {
            throw new UnsupportedOperationException();
        }
        public int indexOf(Object o)            {return list.indexOf(o);}
        public int lastIndexOf(Object o)        {return list.lastIndexOf(o);}
        public boolean addAll(int index, Collection<? extends E> c) {
            throw new UnsupportedOperationException();
        }
        @Override
        public void replaceAll(UnaryOperator<E> operator) {
            throw new UnsupportedOperationException();
        }
        @Override
        public void sort(Comparator<? super E> c) {
            throw new UnsupportedOperationException();
        }
        public ListIterator<E> listIterator()   {return listIterator(0);}
        public ListIterator<E> listIterator(final int index) {
            return new ListIterator<E>() {
                private final ListIterator<? extends E> i
                    = list.listIterator(index);
                public boolean hasNext()     {return i.hasNext();}
                public E next()              {return i.next();}
                public boolean hasPrevious() {return i.hasPrevious();}
                public E previous()          {return i.previous();}
                public int nextIndex()       {return i.nextIndex();}
                public int previousIndex()   {return i.previousIndex();}
                public void remove() {
                    throw new UnsupportedOperationException();
                }
                public void set(E e) {
                    throw new UnsupportedOperationException();
                }
                public void add(E e) {
                    throw new UnsupportedOperationException();
                }
                @Override
                public void forEachRemaining(Consumer<? super E> action) {
                    i.forEachRemaining(action);
                }
            };
        }
复制代码

UnmodifiableList 对会对 list 的修改类型方法 进行重写,令其抛出异常,就会让其他使用者无法调用 list 中修改类型的方法来修改数据了

但是在 调用 list 的 get 方法之后,还是会修改到单项的数据,例如

ShoppingCartItem item = items.get(0);
item.setPrice(19.0);
复制代码

这时候,我们应该在返回list的时候,返回一个数据的 拷贝(深拷贝) ,这样子就不会对原数据做出修改了。

我们可以如下修改

//数据类继承Cloneable接口,重写clone()方法,使得其可继承
public class ShoppingCartItem implements Cloneable{
    private String name;
    private int price;
    public void setName(String name) {
        this.name = name;
    }
    public void setPrice(int price) {
        this.price = price;
    }
    public ShoppingCartItem(String name, int price) {
        this.name = name;
        this.price = price;
    }
    public String getName() {
        return name;
    }
    public int getPrice() {
        return price;
    }
    @Override
    public ShoppingCartItem clone() {
        try {
            return (ShoppingCartItem) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
}
public class ShoppingCart {
  ...
    public List<ShoppingCartItem> getItems() {
        List<ShoppingCartItem> copyItems = new ArrayList<>();;
        for (ShoppingCartItem i : items){
            copyItems.add(i.clone());
        }
        return Collections.unmodifiableList(copyItems);
    }
  ...
}
复制代码

如上实现深拷贝,数据就不可修改原数据的单项数据了😁



相关文章
|
18天前
|
设计模式 存储 Java
23种设计模式,享元模式的概念优缺点以及JAVA代码举例
【4月更文挑战第6天】享元模式(Flyweight Pattern)是一种结构型设计模式,旨在通过共享技术有效地支持大量细粒度对象的重用。这个模式在处理大量对象时非常有用,特别是当这些对象中的许多实例实际上可以共享相同的状态时,从而可以减少内存占用,提高程序效率
33 4
|
18天前
|
设计模式 Java 中间件
23种设计模式,适配器模式的概念优缺点以及JAVA代码举例
【4月更文挑战第6天】适配器模式(Adapter Pattern)是一种结构型设计模式,它的主要目标是让原本由于接口不匹配而不能一起工作的类可以一起工作。适配器模式主要有两种形式:类适配器和对象适配器。类适配器模式通过继承来实现适配,而对象适配器模式则通过组合来实现
30 4
|
22天前
|
设计模式 Java 数据库
Java设计模式精讲:让代码更优雅、更可维护
【4月更文挑战第2天】**设计模式是解决软件设计问题的成熟方案,分为创建型、结构型和行为型。Java中的单例模式确保类仅有一个实例,工厂方法模式让子类决定实例化哪个类。适配器模式则协调不兼容接口间的合作。观察者模式实现了一对多依赖,状态变化时自动通知相关对象。学习和适当应用设计模式能提升代码质量和可维护性,但需避免过度使用。设计模式的掌握源于实践与不断学习。**
Java设计模式精讲:让代码更优雅、更可维护
|
14天前
|
设计模式 算法 Java
23种设计模式,模板方法模式的概念优缺点以及JAVA代码举例
【4月更文挑战第10天】模板方法模式是一种行为设计模式,它定义了一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些特定步骤。
15 0
|
15天前
|
设计模式 Java
23种设计模式,状态模式的概念优缺点以及JAVA代码举例
【4月更文挑战第9天】状态模式是一种行为设计模式,允许一个对象在其内部状态改变时改变它的行为,这个对象看起来似乎修改了它的类。
28 4
|
17天前
|
设计模式 Java
23种设计模式,命令模式的概念优缺点以及JAVA代码举例
【4月更文挑战第7天】命令模式是一种行为设计模式,它将请求或简单操作封装为一个对象。这种模式允许用户通过调用对象来参数化其他对象的方法,并能保存、排队和执行方法调用。
21 1
|
20天前
|
设计模式 Java Windows
23种设计模式,抽象工厂模式的概念优缺点以及JAVA代码举例
【4月更文挑战第10天】抽象工厂模式是一种创建型设计模式,它提供了一个接口用于创建相关或依赖对象的家族,而不需要指定具体类。该模式允许客户端在不知道具体类的情况下,通过其共同的接口来创建一组产品。
27 7
|
1月前
|
设计模式 数据采集 缓存
设计模式取舍之道:代码复杂度权衡
设计模式取舍之道:代码复杂度权衡
39 1
|
4月前
|
设计模式 关系型数据库 程序员
UML中常用设计模式OCP、单例模式、简单工厂模式等模式讲解及C#中代码实现(附源码)
UML中常用设计模式OCP、单例模式、简单工厂模式等模式讲解及C#中代码实现(附源码)
44 0
|
4月前
|
设计模式 自然语言处理 编译器
二十三种设计模式全面解析-解释器模式(Interpreter Pattern):用代码诠释语言的魅力
二十三种设计模式全面解析-解释器模式(Interpreter Pattern):用代码诠释语言的魅力