`
jaesonchen
  • 浏览: 313042 次
  • 来自: ...
社区版块
存档分类
最新评论

复合优先于继承

 
阅读更多
public class CompositionOverInheritance {
	public static void main(String[] args) {
		InstrumentedSet<String> st = new InstrumentedSet<String>(new HashSet<String>());
		InstrumentedSet<String> st1 = new InstrumentedSet<String>(new HashSet<String>());
		st.addAll(Arrays.asList("chen", "chenzq", "jaeson"));
		st1.addAll(Arrays.asList("chen", "chenzq", "jaeson"));
		System.out.println(st.getAddCount());
		System.out.println(st.equals(st1));
		
		//使用继承导致的计数错误
		System.out.println("implements by inheritance......");
		InstrumentedHashSet<String> hs = new InstrumentedHashSet<String>();
		InstrumentedHashSet<String> hs1 = new InstrumentedHashSet<String>();
		hs.addAll(Arrays.asList("chen", "chenzq", "jaeson"));
		hs1.addAll(Arrays.asList("chen", "chenzq", "jaeson"));
		System.out.println(hs.getAddCount());
		System.out.println(hs1.equals(st1));
	}
}
//增加集合计数器
class InstrumentedSet<E> extends ForwardingSet<E> {
	private int addCount = 0;
	public InstrumentedSet(Set<E> s) {
		super(s);
	}
	@Override public boolean add(E e) {
		
		addCount++;
		return super.add(e);
	}
	@Override public boolean addAll(Collection<? extends E> c) {
		addCount += c.size();
		return super.addAll(c);
	}
	public int getAddCount() {
		return addCount;
	}
}
class ForwardingSet<E> implements Set<E> {
	private final Set<E> s;
	public ForwardingSet(Set<E> s) { this.s = s; }
	public void clear() { s.clear(); }
	public boolean contains(Object o) { return s.contains(o); }
	public boolean isEmpty() { return s.isEmpty(); }
	public int size() { return s.size(); }
	public Iterator<E> iterator() { return s.iterator(); }
	public boolean add(E e) { return s.add(e); }
	public boolean remove(Object o) { return s.remove(o); }
	public boolean containsAll(Collection<?> c)	{ return s.containsAll(c); }
	public boolean addAll(Collection<? extends E> c) { return s.addAll(c); }
	public boolean removeAll(Collection<?> c) { return s.removeAll(c); }
	public boolean retainAll(Collection<?> c) { return s.retainAll(c); }
	public Object[] toArray() { return s.toArray(); }
	public <T> T[] toArray(T[] a) { return s.toArray(a); }
	@Override public boolean equals(Object o) { return s.equals(o); }
	@Override public int hashCode() { return s.hashCode(); }
	@Override public String toString() { return s.toString(); }
}
//继承时由于不了解超类的实现细节导致的错误
@SuppressWarnings("all")
class InstrumentedHashSet<E> extends HashSet<E> {
    private int addCount = 0;
    
    public int getAddCount() {
    	return this.addCount;
    }
    
    @Override
    public boolean add(E e){
        addCount++;
        return super.add(e);
    }

    @Override
    public boolean addAll(Collection<? extends E> c){
        addCount += c.size();
        return super.addAll(c);
    }
}

 输出为:
3
true
implements by inheritance......
6
true

 

 

 * 使类和成员的可访问性最小化:
   区别设计良好的模块和设计不好的模块,最重要因素在于,这个模块相对于外部的其他模块而言,  

   是否隐藏其内部数据和其他实现细节。
   设计良好的模块会隐藏所有的实现细节,把API和它的实现清晰地隔离开来。模块之间只通过API进行

   通信,不需要知道其他模块的内部工作情况(封装)。
   封装可以有效地解除组成系统的各模块之间的耦合,使得这些模块可以独立地进行开发、测试、优化、修改。

   在public类中使用public访问方法而不是public field:
   如果public类在它所在的包外部进行访问,就提供访问方法,以保留将来改变该类的内部表示法的灵活性。

 * **********************************************************************
 * 使类可变性最小化:
   为了使类成为不可变,必须遵循以下规则:
   1.不要提供任何会修改对象状态的方法。
   2.保证类不会被扩张。一般做法是使这个类成为final。
   3.使所有的field数据域都成为final。
   4.使所有的field数据域都成为private。
   5.确保对于任何可变组件的互斥访问。如果类具有指向可变对象的field域,则必须确保该类的客户端无法获得

     指向这些对象的引用。并且永远不使用客户端提供的对象引用初始化field域。
  

   不可变对象本质上是线程安全的,它们不要求同步。当多个线程并发访问这样的对象时,它们不会遭到破坏。

   不可变对象可以被自由地共享。


   坚决不要为每个getter编写一个相应的setter,除非有很好的理由要让类成为可变类,否则就应该是不可变的。
   构造器应该创建完全初始化的对象,并建立起所有的约束关系,不要在构造器或者静态工厂之外再提供public

   的初始化方法,同样也不应该提供重新初始化方法。

 * **********************************************************************
 * 复合优先于继承:
   继承是实现代码重用的有力手段,但它并非总是完成这项工作的最佳工具。
   在包内部实现继承是非常安全的,在那里子类和超类的实现都处在同一个程序员的控制下。
   对于专门为了继承而设计,并具有良好的说明文档的类来说,使用继承也是非常安全的。
   然而对普通的具体类进行跨越包边界的继承,则是非常危险的。
   继承打破了封装性,子类依赖于其超类中特定功能的实现细节。超类可能随着发行版本的不同而有所变化。

   因此子类可能遭到破坏,即使它的代码完全没有改变。

 * 复合替代继承:不扩展现有的类,而是在新类中增加一个私有域,引用现有类的一个实例。

   特别是那些实现了标准接口的类。新类中的每个方法都可以调用被包含的现有类实例中对应的方法,

   并返回它的结构。这种方式被称为转发(forwarding)。
   这样得到的类将会非常稳固,它不依赖于现有类的实现细节。即使现有类添加了新的方法,也不会影响新的类。
   复合类被称为包装类,这正是Decorator模式的应用。


 * *********************************************************************
 * 继承的功能非常强大,但它违背了封装原则,只有当子类和超类之间确实存在子类型关系时,才适合使用继承。

   要么为继承而设计,并提供说明文档,要么禁止继承:
   该类的文档必须精确地描述覆盖每个方法所带来的影响。
   为了允许继承,类必须遵循一些约定:构造器决不能调用可被覆盖的方法,无论是直接调用还是间接调用。
   超类的构造器在子类之前运行,所以子类中覆盖版本的方法将会在子类的构造器之前就先被调用。
   如果该覆盖版本的方法依赖于子类构造器的任何初始化操作,该方法将不会如预期般运行。
 
 * 禁止继承的方法:把类声明为final的。另一种办法是把所有构造器都设置为private,并增加public static的

   静态工厂方法替代构造器。

 * 覆盖:子类方法的返回值和抛出异常必须小于等于父类方法的返回类型和声明异常,访问限制符必须大于

   等于父类方法的访问限制符。
 

分享到:
评论

相关推荐

    编写高效优雅Java程序.pdf

    5. 复合优先于继承:复合可以避免继承的缺陷,如破坏封装性和依赖于父类的实现。 6. 接口优于抽象类:接口可以提供更加灵活的设计方式,可以使得类更加灵活和可扩展。 7. 谨慎使用可变参数:可变参数可以使代码...

    编写高效优雅Java程序.docx

    * 复合优先于继承,避免继承容易破坏封装性。 * 接口优于抽象类,java是单继承的,但是类允许实现多个接口。 * 方法可变参数要谨慎使用,避免传0个参数的参数个数在1~多个之间。 * 精确计算,避免使用float和double...

    对标年薪60W阿里P7的目前主流企业使用最高频的面试题库.pdf

    例如,应该避免创建不必要的对象,尽量使类和成员的可访问性最小化,复合优先于继承,接口优于抽象类等。此外,方法的设计中要注意可变参数的使用、异常的处理、返回值的处理等。 性能优化的知识点包括性能评价/...

    JVM与性能优化知识点整理.pdf

    - **复合优先于继承**:使用组合而非继承,可以减少代码的耦合度,提高灵活性。 - **接口优于抽象类**:在多数情况下,接口提供了一种更加灵活的方式来定义类的行为。 ##### 2. 方法 - **可变参数要谨慎使用**:可...

    css第03天.pdf

    层叠性遵循“就近原则”,即样式越接近元素,其效果越优先。当样式不冲突时,它们将并存,而不会相互覆盖。 继承性则是CSS中的一种特性,允许子元素从父元素那里继承某些样式,如文本颜色、字号等。继承可以简化...

    面向对象基本原则 面向对象基本原则

    例如,通过组合,我们可以创建一个包含多个不同功能的类的复合体,而不需要这些功能之间存在继承关系。 以上原则为面向对象设计提供了坚实的理论基础,它们共同构成了面向对象编程语言中最重要的设计理念之一。遵循...

    考研大纲c++

    七、继承与复合 继承是C++语言中的一种机制,它允许一个类继承另一个类的成员变量和成员函数。继承包括继承中的存取控制、构造、析构的调用顺序、私有继承、运算符重载与继承、upcasting等。 八、多态性与虚函数 ...

    9452答案(1)C++期末考试题库.docx

    表达式`7.5+1/2+45%10`中,整数除法和模运算优先于浮点数加法,因此结果为12.5。 C++的参数传递机制有两种:传值和传地址。如果需要在函数内部修改实参的值或者返回多个值,通常使用传地址的方式,即通过指针传递。...

    编写高效优雅Java程序Java系列2021.pdf

    - **复合优于继承**:复合避免了子类对父类实现的依赖,增强了设计的灵活性和封装性。 - **接口优于抽象类**:Java支持单一继承,但可以实现多个接口。当业务变化时,更适合通过增加接口来实现,而不是修改抽象类...

    Python面向对象方面的答辩

    Python面向对象编程思想的核心概念和设计原则 面向对象是一种编程思想,它以人类对现实世界的观察为...6. 组合复用原则:优先使用组合,次要使用继承。 这些原则可以帮助我们编写更加灵活、可维护、可扩展的代码。

    java面向对象编程、类的封装、接口和基本类库练习题.doc

    3. 类包含数据变量和方法,是Java中的复合数据类型,Java的类只支持单继承。 4. 可以作为类及其成员的修饰符有protected和public,但题目中问的是不正确的选项,所以答案可能是其他选项。 5. 公共修饰符public不能...

    第3章使用CSS技术美化网页-教学设计.docx

    继承性允许子元素继承父元素的一些样式,而优先级则是根据CSS规则的来源和特定性来确定哪些规则优先应用。 教学过程中,教师可以采用问题引导的方式激发学生思考,如回顾HTML的`&lt;!DOCTYPE&gt;`标记的作用,强调其在...

    C++良好的编程风格.pdf

    在表达式和基本语句的编写中,了解运算符优先级,合理使用复合表达式,以及编写高效且逻辑清晰的IF语句和循环语句是基础。此外,还应当注意 SWITCH 语句的使用和 GOTO 语句的限制,以避免代码混乱。 常量的使用在...

    计算机软件技术基础 修订版

    第二章 高级程序设计方法.ppt:这一章节主要探讨了如何编写高效且可维护的代码,涵盖面向对象编程的基本概念,如类、对象、继承、多态等。此外,还可能涉及函数式编程和泛型编程,以及设计模式在实际开发中的应用。 ...

    软件 设计模式 论文

    3. **优先使用对象组合**:相对于继承,设计模式更多地推荐使用对象组合的方式来构建组件。这种方式更加灵活,可以更容易地扩展和修改组件的行为。例如,装饰器模式允许动态地给一个对象添加一些额外的职责,而不必...

    蓝桥杯python试题题库及答案说明.zip

    此外,试题还可能涉及到Python的高级特性,如列表、元组、字典、集合等复合数据结构的运用,以及面向对象编程的概念,如类与对象、继承、封装和多态。对于算法部分,考生需要掌握基本的排序算法(如冒泡排序、选择...

    学习CSS优化的十八项技巧

    例如,在`&lt;p class="update"&gt;`这样的元素中,`class="update"`的样式将优先于元素`p`的默认样式应用,这一原则在处理复杂的样式层级时尤为重要。 #### 技巧八:灵活运用多重class定义 一个HTML元素可以拥有多个...

    【JVM和性能优化】4. 编写高效优雅Java代码常用方法

    优先使用复合胜过继承8.接口优于抽象类9. 可变参数谨慎使用10. 尽量不要返回NULL,尽量返回零数组或集合11.优先使用标准异常12.尽量使用枚举替换int13. 局部变量作用域最小化14. 对于精度技术不用float或double15....

Global site tag (gtag.js) - Google Analytics