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

简介: 在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);
    }
  ...
}
复制代码

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



相关文章
|
8天前
|
设计模式 算法 数据库连接
PHP编程中的设计模式:提升代码的可维护性与扩展性
在软件开发的世界里,设计模式是解决常见问题的经典方法。对于PHP开发者而言,掌握这些模式不仅能够提高代码质量,还能让开发过程更加高效。本文将介绍几个关键的设计模式,并通过实例展示如何将这些理念应用到实际项目中去。
17 0
|
1月前
|
设计模式 存储 C#
|
1月前
|
设计模式 算法 C#
23种设计模式【C#代码举例】(上)
23种设计模式【C#代码举例】(上)
|
2月前
|
设计模式 Java
Java中设计模式及举例代码
Java中设计模式及举例代码
16 0
|
3月前
|
设计模式 算法 Java
23种设计模式,访问者模式的概念优缺点以及JAVA代码举例
【4月更文挑战第10天】访问者模式是一种将算法与对象结构分离的设计模式。这种模式主要用于执行一个操作(或一组操作)在一个对象结构的各元素上,它可以在不修改各元素的类的前提下定义新的操作。
38 2
|
3月前
|
设计模式 前端开发 API
写出易维护的代码|React开发的设计模式及原则
本文对React社区里出现过的一些设计模式进行了介绍,并讲解了他们遵循的设计原则。
|
3月前
|
设计模式 存储 Java
C++从入门到精通:3.5设计模式——提升代码可维护性与可扩展性的关键
C++从入门到精通:3.5设计模式——提升代码可维护性与可扩展性的关键
|
4天前
|
设计模式 uml
设计模式-------------工厂模式之工厂方法模式(创建型)
工厂方法模式是一种创建型设计模式,它通过定义一个用于创建对象的接口,让子类决定实例化哪一个类,从而实现类的实例化推迟到子类中进行,提高了系统的灵活性和可扩展性。
设计模式-------------工厂模式之工厂方法模式(创建型)
|
4天前
|
设计模式 uml C语言
设计模式----------工厂模式之简单工厂模式(创建型)
这篇文章详细介绍了简单工厂模式,包括其定义、应用场景、UML类图、通用代码实现、运行结果、实际应用例子,以及如何通过反射机制实现对象创建,从而提高代码的扩展性和维护性。
设计模式----------工厂模式之简单工厂模式(创建型)
|
5天前
|
设计模式 uml
设计模式-------------工厂模式之工厂方法模式(创建型)
工厂方法模式是一种创建型设计模式,它通过定义一个用于创建对象的接口,让子类决定实例化哪一个类,从而实现类的实例化推迟到子类中进行,提高了系统的灵活性和可扩展性。