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

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

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



相关文章
|
2天前
|
设计模式 Java
Java设计模式:组合模式的介绍及代码演示
组合模式是一种结构型设计模式,用于将多个对象组织成树形结构,并统一处理所有对象。例如,统计公司总人数时,可先统计各部门人数再求和。该模式包括一个通用接口、表示节点的类及其实现类。通过树形结构和节点的通用方法,组合模式使程序更易扩展和维护。
Java设计模式:组合模式的介绍及代码演示
|
5天前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提高代码的可维护性与扩展性
在本文中,我们将深入探讨PHP编程语言中设计模式的重要性,以及如何通过应用这些模式来提高代码的可维护性和扩展性。设计模式是一套被反复使用、经过分类编目的代码设计经验的总结。它们代表了最佳的实践,能帮助开发者编写出更加健壮、灵活和可复用的代码。本文将介绍几种常见的设计模式,并通过PHP代码示例展示其应用。
|
22天前
|
设计模式 Java
重构你的代码:探索Java中的混合、装饰器与组合设计模式
【8月更文挑战第30天】在软件开发中,设计模式为特定问题提供了结构化的解决方案,使代码更易理解、维护及扩展。本文将介绍三种常用的 Java 设计模式:混合模式、装饰器模式与组合模式,并附有示例代码展示实际应用。混合模式允许通过继承多个接口或抽象类实现多重继承;装饰器模式可在不改变对象结构的情况下动态添加新功能;组合模式则通过树形结构表示部分-整体层次,确保客户端处理单个对象与组合对象时具有一致性。
15 1
|
1月前
|
设计模式 算法 安全
Java编程中的设计模式:提升代码的可维护性和扩展性
【8月更文挑战第19天】在软件开发的世界里,设计模式是解决常见问题的一种优雅方式。本文将深入探讨Java编程语言中常用的几种设计模式,并解释如何通过这些模式来提高代码的可维护性和扩展性。文章不涉及具体的代码实现,而是侧重于理论和实践相结合的方式,为读者提供一种思考和改善现有项目的新视角。
|
1月前
|
设计模式 Java
常用设计模式介绍~~~ Java实现 【概念+案例+代码】
文章提供了一份常用设计模式的全面介绍,包括创建型模式、结构型模式和行为型模式。每种设计模式都有详细的概念讲解、案例说明、代码实例以及运行截图。作者通过这些模式的介绍,旨在帮助读者更好地理解源码、编写更优雅的代码,并进行系统重构。同时,文章还提供了GitHub上的源码地址,方便读者直接访问和学习。
常用设计模式介绍~~~ Java实现 【概念+案例+代码】
|
20天前
|
前端开发 C# 设计模式
“深度剖析WPF开发中的设计模式应用:以MVVM为核心,手把手教你重构代码结构,实现软件工程的最佳实践与高效协作”
【8月更文挑战第31天】设计模式是在软件工程中解决常见问题的成熟方案。在WPF开发中,合理应用如MVC、MVVM及工厂模式等能显著提升代码质量和可维护性。本文通过具体案例,详细解析了这些模式的实际应用,特别是MVVM模式如何通过分离UI逻辑与业务逻辑,实现视图与模型的松耦合,从而优化代码结构并提高开发效率。通过示例代码展示了从模型定义、视图模型管理到视图展示的全过程,帮助读者更好地理解并应用这些模式。
35 0
|
1月前
|
设计模式 前端开发 算法
"揭秘前端开发的隐藏武器:掌握这些设计模式,让你的代码优雅升级!"
【8月更文挑战第21天】设计模式为前端开发提供了解决常见问题的模板,助力编写清晰、可维护的代码。本文概览了几种关键模式:模块模式通过立即执行函数表达式实现封装;单例模式确保全局唯一实例,适用于状态管理;工厂模式根据条件创建不同类型的对象;观察者模式建立对象间的依赖,便于事件处理和数据绑定;策略模式封装可互换的算法,提高灵活性。掌握这些模式能显著提升代码质量和开发效率。
27 0
|
6天前
|
设计模式 算法 安全
设计模式——模板模式
模板方法模式、钩子方法、Spring源码AbstractApplicationContext类用到的模板方法
设计模式——模板模式
|
1月前
|
设计模式
设计模式-单一职责模式
设计模式-单一职责模式
|
1月前
|
设计模式 XML 存储
【二】设计模式~~~创建型模式~~~工厂方法模式(Java)
文章详细介绍了工厂方法模式(Factory Method Pattern),这是一种创建型设计模式,用于将对象的创建过程委托给多个工厂子类中的某一个,以实现对象创建的封装和扩展性。文章通过日志记录器的实例,展示了工厂方法模式的结构、角色、时序图、代码实现、优点、缺点以及适用环境,并探讨了如何通过配置文件和Java反射机制实现工厂的动态创建。
【二】设计模式~~~创建型模式~~~工厂方法模式(Java)