100 Questions to Master OOP in Dart
This is Part 11 of the Object-Oriented Dart series — the part where you stop reading and start proving it. The previous ten parts taught the concepts; this question bank turns them into mastery.
How to use this bank:
- There are 100 questions, grouped by topic and tagged [Basic], [Medium], or [Advanced], and marked (Theory) or (Coding).
- Each one has a Hint — the logic, approach, or key idea, deliberately not a full solution. The struggle before the hint is where the learning happens, so try each one cold first.
- For (Coding) questions, write and run real Dart (dartpad.dev is perfect — no setup). Code you don't run is code you don't understand yet.
- Don't binge. Do 10–15 a day, revisit the matching part when one stumps you, and re-attempt anything you needed the hint for a week later.
If you can answer all 100 without hints — explaining the why, not just the what — you genuinely understand OOP in Dart. Let's go.
Every hint points back to the part that covers it, so you always know where to review. Pen and paper for theory; DartPad for coding.
Section A — Foundations: classes, objects, this (Q1–10)
Q1. [Basic] (Theory) In your own words, what is the difference between a class, an object, and an instance?
Hint
Think blueprint vs. building. One of the three words is just a synonym for one of the others. Cover it in Part 1.
Q2. [Basic] (Theory) Dart says "everything is an object." Give two concrete things you can do because of that which you couldn't in a language with primitive types.
Hint
Try calling a method on a literal number. What can 42 or 3.14 do on their own?
Q3. [Basic] (Coding) Model a Laptop class with brand, ram, and price. Create three laptops in a list and print the brand of each.
Hint
Constructor with initializing formals (this.brand), a List<Laptop>, then a for-in loop. No methods needed yet.
Q4. [Basic] (Coding) Add a describe() method to Laptop that returns a one-line summary string using all three fields.
Hint
Inside the method the fields are in scope directly — no prefix needed. String interpolation ('$brand ...') and arrow syntax keep it tidy.
Q5. [Medium] (Theory) When is the this keyword required rather than optional? Give the one situation where omitting it causes a silent bug.
Hint
Think about a constructor or setter parameter that has the same name as a field. What does size = size actually do?
Q6. [Medium] (Theory) Why is if (x is Animal) preferred over if (x.runtimeType == Animal)? Name the two distinct advantages.
Hint
One advantage is about subtypes; the other is a convenience the compiler gives you inside the if block. Search "type promotion."
Q7. [Medium] (Coding) Given List<Object> items mixing Laptops and Strings, print only the laptops' summaries and skip everything else.
Hint
Loop and use is to both filter and promote. After if (item is Laptop), you can call Laptop methods with no cast.
Q8. [Advanced] (Theory) Predict and explain:
var a = Laptop('Dell', 16, 1000);
var b = a;
b.ram = 32;
print(a.ram); // ?
Hint
Objects are reference types. Does var b = a copy the object or the pointer to it? Part 1, final question.
Q9. [Advanced] (Coding) Write a function Laptop copyOf(Laptop other) that returns a new, independent laptop with the same values, then prove mutating the copy doesn't affect the original.
Hint
The whole point is to not return the same reference. Build a brand-new Laptop(...) from the other's fields. (This is the manual version of what copyWith does in real apps.)
Q10. [Advanced] (Theory) What does it mean that a method "automatically operates on whichever instance you called it on"? Tie your answer to how this is passed.
Hint
Mentally rewrite sam.describe() as a free function describe(sam). What hidden first argument is this?
Section B — Constructors (Q11–22)
Q11. [Basic] (Theory) What do you get for free if you declare a class with no constructor, and what happens to that freebie the moment you add one of your own?
Hint
It's unnamed and zero-argument. Part 2, "default constructor."
Q12. [Basic] (Coding) Write a User class with a required named name and an optional named isAdmin defaulting to false. Build one admin and one normal user.
Hint
Named params live in {}; combine required this.name with this.isAdmin = false.
Q13. [Basic] (Theory) Explain the difference between a named parameter and a named constructor. They sound the same — they're not.
Hint
One changes how you pass arguments to a single constructor; the other is a whole separate constructor with a .name.
Q14. [Medium] (Coding) Give User a User.guest() named constructor (name 'Guest', not admin). Then rewrite it as a redirecting constructor.
Hint
Direct version sets fields in an initializer list; redirecting version forwards with : this(name: 'Guest') and has no body.
Q15. [Medium] (Coding) Build a Temperature class with a final celsius and a Temperature.fromFahrenheit(double f) constructor that converts in an initializer list.
Hint
The conversion must run before the body because celsius is final. Put : celsius = (f - 32) * 5 / 9 after the colon.
Q16. [Medium] (Theory) Why can't an initializer list access this, and why is that perfectly fine for setting up final fields?
Hint
What stage of construction is the object in when the initializer list runs? What can the list still read (parameters)?
Q17. [Medium] (Coding) Add an assert to a Person(name, age) constructor that rejects negative ages, and show where in the constructor it goes.
Hint
assert belongs in the initializer list: Person(this.name, this.age) : assert(age >= 0).
Q18. [Advanced] (Coding) Make an immutable Color (final r, g, b) with a const constructor. Then prove that two const Color(255, 0, 0) values are identical, but two non-const ones are not.
Hint
const constructor needs all-final fields. Canonicalization only kicks in when you write const at the call site. Use identical(a, b).
Q19. [Advanced] (Coding) Write a Currency class so that Currency('USD') returns the same cached instance every time. Which constructor type, and what's the supporting machinery?
Hint
factory + a static Map cache + a private named constructor (Currency._). putIfAbsent does the heavy lifting.
Q20. [Advanced] (Coding) Create an abstract class Shape with a factory Shape(String kind) returning a Circle or Square based on the string. Why can a factory do this when a generative constructor can't?
Hint
A factory returns an object instead of initializing this, so it's free to pick the concrete subtype. A switch expression makes the body clean.
Q21. [Advanced] (Theory) You write var p = ImmutablePoint(1, 2) (no const) with a const constructor. Is p a compile-time constant? Are two such objects identical? Explain.
Hint
A const constructor only enables constness — you still have to request it. No const keyword at the call site means an ordinary runtime instance.
Q22. [Advanced] (Theory) Why is this forbidden inside a factory constructor, and how does that very restriction connect to what makes factories useful?
Hint
There's no single "new object being initialized" — the factory might return a cached one, a subtype, or something built elsewhere.
Section C — Encapsulation: privacy, getters/setters, statics (Q23–33)
Q23. [Basic] (Theory) How do you make a member private in Dart? What scope is it private to — and why does that surprise people from Java?
Hint
Underscore prefix. The scope is the library (file), not the class. Part 3.
Q24. [Basic] (Coding) Take class Game { int score = 0; } and encapsulate it so score can be read but only increased through an addPoints method that rejects negatives.
Hint
Make _score private, add a get score, and make addPoints the only mutator with a guard clause.
Q25. [Basic] (Coding) Give a Rectangle(width, height) read-only area and perimeter getters. No stored fields for those two.
Hint
double get area => width * height; — computed on demand, nothing stored.
Q26. [Medium] (Theory) What's the difference between a getter and a regular method, and what's the decision rule for choosing one over the other?
Hint
Parentheses vs. none; "is-a-property" vs. "does-an-action."
Q27. [Medium] (Coding) Write a Temperature with a fahrenheit getter and setter, where setting fahrenheit updates the underlying _celsius. Show t.fahrenheit = 212 makes t.celsius become 100.
Hint
The setter does the reverse conversion: set fahrenheit(f) => _celsius = (f - 32) * 5 / 9;. The getter and setter share _celsius.
Q28. [Medium] (Theory) Two classes A and B sit in the same file. Can A read B's _secret? What about across two files? Why?
Hint
Privacy is per library. Same file = same library.
Q29. [Medium] (Coding) A Team holds a private List<String> _members. Expose them for reading without letting callers mutate the internal list. Show that team.members.add(...) throws.
Hint
Returning _members directly is a leak. Return List.unmodifiable(_members) from the getter.
Q30. [Medium] (Coding) Track how many Widget objects have ever been created, exposed as a read-only class-level count.
Hint
static int _count bumped in the constructor, plus a static int get count. Accessed via the class, not an instance.
Q31. [Advanced] (Theory) Explain final vs. late final for a field. What new failure mode does late introduce, and when does it occur?
Hint
late trades a compile-time guarantee for a runtime one. What happens if you read before assigning? Search "LateInitializationError."
Q32. [Advanced] (Coding) Make a Config whose settings are produced by an expensive loader that runs only on first access — and never if settings is never read. Prove the lazy behavior with a print statement.
Hint
late final settings = _load();. The initializer is deferred to first read. Put a print inside _load to observe when it runs.
Q33. [Advanced] (Theory) A static method can't see instance fields or this. Explain why, and derive from that the rule for when a method should be static.
Hint
Static members belong to the class, not an object — so there's no "current object." When does a method genuinely not need a specific instance?
Section D — Methods, operators, cascades, equality (Q34–45)
Q34. [Basic] (Theory) What does the operator keyword let you do, and why should you use it sparingly?
Hint
It defines what +, ==, [], etc. mean for your type. Overload only when the meaning is obvious. Part 4.
Q35. [Basic] (Coding) Create a Vector(x, y) and overload + and - so a + b and a - b return new vectors. Add a readable toString.
Hint
Vector operator +(Vector o) => Vector(x + o.x, y + o.y); — an operator is just a method with a symbol name.
Q36. [Basic] (Coding) Use a cascade to configure a StringBuffer so it ends up containing [1, 2, 3], then print it.
Hint
..write(...) chains on one buffer; wrap the whole thing in parens before .toString().
Q37. [Medium] (Theory) By default, what does == compare for two objects of your custom class? Why is that often not what you want?
Hint
Default is identity (same object in memory), not value. Two Money(500) are not equal by default.
Q38. [Medium] (Coding) Give a Money(cents) value equality: two Money(500) should be == and behave correctly in a Set. What two things must you override, and together?
Hint
== (parameter typed Object, narrow with is) and hashCode. For one field, cents.hashCode; for many, Object.hash(...).
Q39. [Medium] (Theory) A class overrides == but not hashCode. Describe the concrete, observable bug this causes in a Set or Map.
Hint
Hash collections find by bucket (hashCode) first, then confirm with ==. Equal objects with different hashes land in different buckets.
Q40. [Medium] (Theory) Why must an overridden == take an Object parameter rather than your own class type?
Hint
You're overriding Object's ==, whose signature is fixed. A narrower parameter wouldn't actually override it.
Q41. [Medium] (Coding) Make a Version(major, minor) implement Comparable<Version> so a list sorts correctly with ..sort().
Hint
compareTo returns negative/zero/positive. Compare major first, fall back to minor. Then [...]..sort().
Q42. [Advanced] (Theory) Explain exactly what a cascade (..) returns, and why that's what enables chaining. How does ?.. differ?
Hint
. returns the member's result; .. discards it and returns the receiver. ?.. skips the whole chain on null.
Q43. [Advanced] (Coding) Make a Multiplier(factor) whose instances are callable like functions: Multiplier(3)(10) returns 30, and [1,2,3].map(triple) works.
Hint
Define a method literally named call. obj(x) becomes obj.call(x).
Q44. [Advanced] (Coding) Make a Money type that supports +, -, <, value equality, and Comparable, then sort a list of them. (Combine four Part-4 ideas.)
Hint
You'll write operator +/-/<, ==+hashCode, and compareTo. Keep cents as the single source of truth.
Q45. [Advanced] (Theory) Contrast a "callable object" (with a call method) against just storing a closure in a field. When is the callable object the better design?
Hint
A callable object is still a full object — multiple methods, constructors, state, can implement interfaces. A closure is just a function value.
Section E — Inheritance & polymorphism (Q46–58)
Q46. [Basic] (Theory) What relationship does inheritance model, and what's the keyword? Give a clean "is-a" example and a clean non-example.
Hint
"is-a" via extends. A Dog is an Animal; a Car is not an Engine (that's "has-a"). Part 5.
Q47. [Basic] (Coding) Make Vehicle with start(), and a Car extends Vehicle that adds honk(). Show a Car can do both.
Hint
Car inherits start() for free; just add honk(). Cascades can call both in one statement.
Q48. [Basic] (Theory) What are the two distinct uses of super?
Hint
One in the constructor (forward to parent constructor), one in a method (call the parent's version).
Q49. [Medium] (Coding) Employee extends Person, where Person has name and Employee adds salary. Forward name to the parent using a super parameter.
Hint
Employee(super.name, this.salary); — super.name feeds Person(this.name).
Q50. [Medium] (Coding) Override describe() in Bird so it prints the parent's line first and then "It can fly." Which pattern is this?
Hint
Call super.describe() first, then add the new line. "Extend, don't replace."
Q51. [Medium] (Theory) @override is optional. Give the concrete bug it catches, with an example of how the bug happens.
Hint
Misspell the method name or change the signature. Without @override, you've silently created a brand-new method that's never called.
Q52. [Medium] (Coding) Build a List<Shape> with a Circle and a Rectangle, then print each area through the common Shape type. Name the mechanism that makes the right area() run.
Hint
Polymorphism / dynamic dispatch. The loop calls area() on a Shape; each object runs its own override.
Q53. [Medium] (Theory) Inheritance vs. composition: give the deciding question and one example of each.
Hint
"is-a" → extends; "has-a" → store a field. Dog is an Animal; Car has an Engine.
Q54. [Advanced] (Theory) In polymorphism, does the variable's declared type or the object's runtime type decide which implementation runs? What does the other one decide?
Hint
Runtime type → which implementation (dispatch). Declared type → which methods you're allowed to call (the contract).
Q55. [Advanced] (Theory) Predict and explain:
class A {
String who() => 'A';
String greet() => 'Hello from ${who()}';
}
class B extends A {
@override
String who() => 'B';
}
print(B().greet()); // ?
Hint
greet() is inherited from A, but who() dispatches on the actual object. What is the object? (This is the "template method" pattern.)
Q56. [Advanced] (Coding) Implement a Shape base with a polymorphic toString() that calls an overridden area(). Add Circle and Square, put them in a list, and print each — plus the total area with fold.
Hint
Shape.toString() can call area(); subclasses override area(). The base's toString will use each subclass's version automatically.
Q57. [Advanced] (Theory) When would you use covariant, and what safety trade-off does it make?
Hint
It lets an override narrow a parameter type (e.g., Cat.chase(Mouse) from Animal.chase(Animal)). The check moves from compile time to runtime.
Q58. [Advanced] (Theory) What is noSuchMethod, and name a real-world tool category that relies on it.
Hint
It intercepts calls to members that don't exist. Mocking/proxy libraries lean on it heavily.
Section F — Abstract classes & interfaces (Q59–67)
Q59. [Basic] (Theory) What does marking a class abstract prevent, and when is that the right call?
Hint
It blocks direct instantiation — right when the type is only a concept (a generic "Shape"). Part 6.
Q60. [Basic] (Coding) Turn class Animal { String makeSound() => ''; } into an abstract class with an abstract makeSound(), then implement Cat and Dog.
Hint
abstract class + String makeSound(); (no body, just ;). Subclasses are now forced to implement it.
Q61. [Medium] (Theory) Dart has no interface keyword for declaring interfaces. So where do interfaces come from, and how do you write a "pure" one?
Hint
Every class implicitly defines an interface. Convention: an abstract class with only abstract methods.
Q62. [Medium] (Coding) Add a concrete introduce() to an abstract Animal that prints "I say (sound)" using the abstract makeSound(). Show a subclass making it work.
Hint
Abstract classes can mix concrete and abstract members. introduce() calls makeSound(), which the subclass supplies — polymorphism wires them.
Q63. [Medium] (Coding) Define Flyer (fly()) and Swimmer (swim()) interfaces, and a Duck that is both.
Hint
class Duck implements Flyer, Swimmer — you can implement many interfaces, but must supply every member.
Q64. [Medium] (Theory) List the three biggest differences between extends and implements.
Hint
(1) inherits code vs. not; (2) one vs. many; (3) super available vs. not.
Q65. [Advanced] (Theory) When you implements a concrete class with ten method bodies, do you inherit those bodies? Explain why this makes implements tedious there, and what you'd use instead to reuse code.
Hint
implements takes only the interface (signatures). You'd re-write all ten. Use extends or a mixin to reuse.
Q66. [Advanced] (Coding) Design a plugin system: an abstract Plugin interface (name getter, run()), two concrete plugins, and a runAll(List<Plugin>). Explain why adding a new plugin requires zero changes to runAll.
Hint
runAll depends only on the abstraction. New plugins just implements Plugin and slot in — abstraction + polymorphism.
Q67. [Advanced] (Coding) Write an abstract class Logger with a factory Logger(String type) that returns a ConsoleLogger or SilentLogger. The caller should never name the concrete classes. Which two ideas combine here?
Hint
Abstraction (the contract) + a factory constructor (Part 2) hiding the concrete choice.
Section G — Mixins (Q68–76)
Q68. [Basic] (Theory) What problem do mixins solve that neither extends nor implements can, and what keyword applies one?
Hint
Reusing real implementation across unrelated classes without single-inheritance pain. Keyword: with. Part 7.
Q69. [Basic] (Coding) Define a Logger mixin with a log(String) method and apply it to two unrelated classes, Server and Client.
Hint
mixin Logger { void log(...) {...} }, then class Server with Logger {}. No shared superclass required.
Q70. [Medium] (Coding) Create Walks and Barks mixins and a Dog that mixes in both. Then make a SmartPhone that extends Device with Camera, GPS.
Hint
Comma-separate mixins after with. Order is extends first, then with.
Q71. [Medium] (Theory) What two things does an on clause do for a mixin?
Hint
Restricts where it can be applied, and grants access to the base type's members (and super).
Q72. [Medium] (Coding) Write a Stats mixin usable only on a Character (which has int level) that adds levelUp(). Show that class Rock with Stats {} won't compile.
Hint
mixin Stats on Character { ... level++ ... }. The on clause both restricts and unlocks access to level.
Q73. [Medium] (Coding) Write a Json mixin with a concrete printJson() that depends on an abstract Map<String, dynamic> toJson() the host class must implement.
Hint
The mixin declares toJson(); (abstract) and implements printJson(). The host fills in toJson. Template behavior.
Q74. [Advanced] (Theory) Predict the output and explain via linearization:
mixin X { String tag() => 'X'; }
mixin Y { String tag() => 'Y'; }
class Z with X, Y {}
print(Z().tag()); // ?
Hint
Mixins apply left-to-right; the last one wins. Chain: Object → X → Y → Z.
Q75. [Advanced] (Theory) Why can't a regular mixin declare a non-default constructor? What do you reach for if you need a type that's both constructible and mixable?
Hint
A mixin isn't instantiated on its own — the host's constructor runs. Need both roles? Use mixin class (giving up on and custom constructors).
Q76. [Advanced] (Coding) Model a game with abstract class Entity (name, health) and two mixins Damageable and Healable, both on Entity. A Player composes both. Show damage/heal in action and explain why a Monster extends Entity with Damageable reuses the same logic.
Hint
on Entity lets both mixins touch health/name safely. The damage logic lives once in the mixin and is reused by any Entity.
Section H — Enums (Q77–84)
Q77. [Basic] (Theory) What problems do enums solve compared to using Strings or ints for a fixed set of options? Name three.
Hint
Closed set, compile-time checking (no typos), complete .values list. Part 8.
Q78. [Basic] (Coding) Define a Suit enum and print every value with its index and name.
Hint
for (final s in Suit.values) then s.index and s.name.
Q79. [Medium] (Theory) Why is a switch over an enum safer without a default clause? What does adding default cost you?
Hint
No default enables exhaustiveness checking — adding a value later becomes a compile error. default silences that safety net.
Q80. [Medium] (Coding) Make an enhanced Coin enum where each value carries its cents (penny=1 … quarter=25), plus a double get dollars. Don't forget the structural rules.
Hint
Values first with constructor args, then ;, then a const constructor, final fields, then methods. The ; after the last value is easy to forget.
Q81. [Medium] (Coding) Create a LogLevel enum (debug, info, warning, error) with a shouldLog(LogLevel min) that returns whether this level is at least as severe as min.
Hint
Severity matches declaration order, so compare index >= min.index.
Q82. [Advanced] (Coding) Build an Operation enum (add, subtract, multiply, divide) where each value carries a symbol and has an apply(a, b) method using an exhaustive switch (this).
Hint
Each value passes its symbol to the const constructor; apply switches over this with no default.
Q83. [Advanced] (Coding) Make a Priority enum implement Comparable<Priority> so a list of priorities sorts low→high.
Hint
enum Priority implements Comparable<Priority> with compareTo comparing index. Even a simple enum can implement interfaces.
Q84. [Advanced] (Theory) An enum can implements and use with, but cannot extends. Explain the asymmetry.
Hint
Every enum implicitly extends Enum, and Dart allows only single inheritance — the extends slot is taken.
Section I — Extensions & extension types (Q85–91)
Q85. [Basic] (Theory) What does an extension method let you do that you otherwise couldn't, and what does this refer to inside one?
Hint
Add members to a type you don't own; this is the extended value. Part 9.
Q86. [Basic] (Coding) Write an extension on String adding a capitalized getter (uppercases the first letter, handles empty strings).
Hint
extension on String { String get capitalized => ... }. Guard isEmpty first to avoid an index error.
Q87. [Medium] (Coding) Add an extension on int with times(void Function() action) that runs the action that many times, so 3.times(() => print('hi')) works.
Hint
this is the integer; loop for (var i = 0; i < this; i++) and call action().
Q88. [Medium] (Coding) Write a generic extension on List<T> with T? get firstOrNull.
Hint
extension X<T> on List<T> { T? get firstOrNull => isEmpty ? null : this[0]; }. The <T> keeps the return type correct.
Q89. [Medium] (Theory) Why does an extension method fail when called on a dynamic variable? Explain "statically resolved."
Hint
Extensions resolve on the declared type at compile time; dynamic has none to match. Result: a runtime NoSuchMethodError.
Q90. [Advanced] (Theory) Contrast dispatch of an overridden method vs. an extension method. If you call an extension through a supertype reference, which version runs — and why does that mean extensions aren't a substitute for real overrides?
Hint
Methods dispatch dynamically (runtime type); extensions dispatch statically (declared type), no polymorphism. The declared type wins, ignoring the real subtype.
Q91. [Advanced] (Coding) Use an extension type to make UserId and ProductId (both over int) into distinct compile-time types so the compiler refuses to mix them — at zero runtime cost. What's the key runtime property?
Hint
extension type UserId(int value) {}. At runtime it is an int (no wrapper/allocation); at compile time it's a separate type. Great for IDs/units.
Section J — Class modifiers, sealed classes & capstone (Q92–100)
Q92. [Basic] (Theory) In one line each: what do base, interface, and final (the class modifiers) permit and forbid from another library?
Hint
base → extend-only; interface → implement-only; final → neither. Part 10.
Q93. [Medium] (Theory) What does sealed do to a class, and what single capability does it unlock that the other modifiers don't?
Hint
Implicitly abstract + subtypes confined to the same library → the compiler knows them all → exhaustive switch.
Q94. [Medium] (Coding) Model sealed class Animal with Dog, Cat, Bird and a String sound(Animal) using an exhaustive switch (no default). Then add Fish and observe what the compiler says.
Hint
All subtypes in one file. Omit default so adding Fish breaks the build until you handle it — that's the feature.
Q95. [Medium] (Coding) Extend Q94 so Dog has a name and the matching case returns "Rex says Woof" using an object pattern that destructures the field.
Hint
Dog(:final name) => '$name says Woof' — checks type and binds name in one step, no cast.
Q96. [Medium] (Theory) Choose the modifier: (a) a Money value type nobody should ever subtype; (b) a PaymentGateway others implement but never extend. Justify each.
Hint
(a) final (fully closed, free to evolve). (b) abstract interface class (implement-only contract).
Q97. [Advanced] (Theory) Compare modelling a closed set of cases with an enum vs. a sealed class. Give the rule of thumb for when each wins.
Hint
Same shape, finite constants → enum. Different per-variant structure/data or multiple instances → sealed class.
Q98. [Advanced] (Coding — Capstone) Build a sealed class Result<T> with Loading, Success(data), Failure(message), and a render(Result<String>) that pattern-matches all three with no default. Explain why a UI literally cannot forget the error state.
Hint
Three same-library subtypes; exhaustive switch with object patterns. Omitting a case is a compile error — that's the guarantee. This is the canonical Flutter state pattern.
Q99. [Advanced] (Coding — Capstone) Write a tiny expression evaluator: sealed class Expr with Num(value), Add(left, right), Mul(left, right), and a recursive int eval(Expr). Evaluate (2 + 3) * 4. Then add a Sub node and note what the compiler forces.
Hint
Each node carries its own structure; eval is an exhaustive recursive switch destructuring with object patterns. Adding Sub breaks eval until handled — the compiler is your checklist.
Q100. [Advanced] (Coding — Grand Capstone) Design a small library management system that uses as many series concepts as you can justify: an abstract LibraryItem (or sealed for exhaustive reporting), concrete Book/Magazine/DVD, value equality on an ISBN (consider an extension type), a Borrowable mixin, an enum for ItemStatus, encapsulated private collections, polymorphic describe(), and an exhaustive switch to compute late fees per item type. No starter code — architect it yourself.
Hint
Don't write it all at once. Sketch the types and relationships first (which is-a, which has-a, which capability): sealed/abstract base for the items; enum ItemStatus; a Borrowable mixin on LibraryItem; ISBN as an extension type or a value class with ==/hashCode; a Library class that hides its _items behind unmodifiable views; and a fee calculator using an exhaustive switch over the item types. Build one slice end-to-end (e.g. Book borrow/return) before adding the rest. If you can finish this cleanly, you've mastered OOP in Dart.
Where to go from here
If you worked through all 100 — especially the coding ones, run and not just read — you now have a working command of object-oriented Dart, from the smallest class to sealed hierarchies with exhaustive pattern matching.
A few suggestions to lock it in:
- Re-attempt anything you needed a hint for, a week later, cold. Spaced repetition is how concepts move from "I recognize it" to "I can wield it."
- Build the grand capstone (Q100) for real. A finished mini-project teaches more than fifty isolated snippets.
- Read good Dart source. The Flutter framework and popular pub.dev packages are master classes in these exact patterns — now you can read them fluently.
That brings the Object-Oriented Dart series to a close — eleven parts, from "what is a class?" to a 100-question gauntlet. Head back to Part 1 any time you want to review, and thanks for going the distance. Now go build something — and make it object-oriented.