The purpose of this exercise is different than those that came before it. Rather than focusing on different programming techniques that can be used to achieve different system properties, the goal in this exercise is to leverage all of that knowledge to design small systems that addresses a higher level problem.
The goal is not to pass tests, to achieve a specific set of detailed functionalities, or to demonstrate language level competencies. Instead, you should construct a design that is able to satisfy the constraints provided by the underlying problem definition. Your solution could be written in code, but there may be some parts of the code that are unspecified in the problem descriptions. You should clearly identify all classes, functions/methods, calls, and control flow that are relevant to solving the given problems. The behavior of these pieces and how they interact to enable meeting the given constraints matters most.
In all cases, you have the additional constraints of good design. Prefer a design that is easier to maintain, easier to use, and harder to misuse.
You are working on a small 3D scene modeling application.
As a part of modeling scenes, you must manage the Textures that determine
visual attributes of objects in the scene.
These attributes can include things like
color, opacity, roughness, light emission, images that may be drawn on an object,
and more.
Users are able to create new textures and specify these attributes to create
a texture that will be used within the scene.
When creating an object in the scene,
they can either create a new Texture or select an existing Texture to
apply to that objects.
Your Goal:
Design a component that manages Textures that can be used in the above scenario.
It should
Texture and acquire an instance
of the Texture so that it can be applied to an object in the scene.
Textures so that a user can select one
of the existing ones if they so choose.
Texture with a specific configuration of
attributes.
The last constraint arises because you care about efficiency, and you noticed
that users had a tendency to create the same texture many times
(even if you provided a list of existing textures). By not creating more than
one instance of a Texture with a given set of attributes, you can save on
resources and performance in practice.
NOTE: This is not a Singleton.
You are managing a data processing pipeline that supports loading data from a source, transforming and computing with the data, and saving the data into a target.
The source of the data can be any one of:
Data loaded from remote sources are untrusted and must be sanitized
to become trusted before they can be used in transformation or computation.
Trusted data can then be used in computations. Computations can involve several different types of operations including:
filtering data based on a conditionsmoothing data based on a neighborhood mapping data based on a function but it is also possible to repeat a sequence of computations on data for
a fixed number of iterations.
These computations themselves produce trusted data.
Given a pipeline with trusted data, you can also save it into either
Every pipeline should end in a saving operation in order to be correct. The data from a pipeline should only be saved once.
Your Goal: Design the API for constructing and executing data processing pipelines. Your API should be easy to use and hard to misuse. It should allow users to flexibly express the ways of loading, transforming, and saving data while ensuring that a constructed pipeline is valid at compile time and can is designed to correctly execute from end to end.
People are complex and multifaceted. Sometimes, they are productive in a work oriented fashion. Sometimes, they are productive in a leisure oriented fashion. In both cases, people will often develop a set of tasks that they wish to perform.
A Person may be given either WorkTasks or LeisureTasks at any time.
These tasks may accumulate.
When a person is working, they will perform WorkTasks,
and when they are playing they will perform LeisureTasks.
A task is performed whenever a Persons performTask method is called.
Tasks of a given type are completed in the order they arrive,
and once a task is completed, a Person safely may forget about it.
A Person may change between work and leisure as needed.
While performing WorkTasks, a person can either be working normally
or working in "crunch" mode. When working normally, a person only
performs one task, but when working in "crunch" mode,
a person will perform 2 tasks every time performTask is called.
They may change into crunch mode specifically after working on LeisureTasks.
But this is unsustainable. They can only perform 6 total tasks before
they must leave crunch mode for a healthier working process.
Your Goal:
Design the API and core implementation for Person and task execution
that enables the above design for modeling how a person can complete their tasks.
Unlike the previous exercises, this one is more freeform. Instead of submitting runnable code, you should submit a PDF with your solutions.
Your solution should still be as precise as code would be, and you might want to express some parts as code. However, because you are not implementing the entirety of a system, you only need to express the parts relevant to your solutions. If you feel that diagrams help to convey your design in some places, you are free to use them.
You can submit your PDF via CourSys as usual.